swift-google-slides-view
Google Slides API の JSON を SwiftUI で描画。A2A アーティファクトのストリーミングに対応
swift-google-slides-view
Render Google Slides API presentation JSON in SwiftUI.
Google Slides API の presentation スキーマ(のセマンティック・サブセット = プロファイル)に準拠した JSON を、SwiftUI で 16:9 スライドとしてレンダリングする Swift Package。LLM エージェントにスキーマ準拠 JSON を生成させ、A2A Artifact ストリーミングで 1 枚ずつ配信する用途を主眼に設計しているが、スキーマとレンダラ自体は LLM にも A2A にも依存しない。
This project is not affiliated with, endorsed by, or sponsored by Google. "Google Slides" is a trademark of Google LLC. The schema vocabulary follows the publicly documented Google Slides API discovery document.
設計原則
- 語彙を発明しない — フィールド名・enum は本家 discovery document と同名。Swift の enum が本家の部分集合であることをテストで強制(enum parity)。North-star: 実際の
presentations.getレスポンス(サブセット)がそのまま decode → レンダリングできること - 依存の向きは内→外 — スキーマは何も知らない。プロトコル依存はアダプタへ、UI 依存は葉へ
- CLI で TDD — レンダラ以外の全ターゲットは UI 非依存で、
swift testが CLI で完結する
ターゲット構成
| ターゲット | 責務 | 依存 |
|---|---|---|
GSlidesSchema |
プロファイルの Codable モデル + vendored discovery doc + 制約カタログ(SSOT) | swift-structured-data |
GSlidesLayout |
コンテンツ → predefinedLayout マッチング、placeholder 解決、EMU 計算 | GSlidesSchema |
GSlidesAssembly |
チャンク列 (payload, append, lastChunk) → presentation 状態の純関数 reducer |
GSlidesSchema |
GSlidesPrompt |
LLM 構造化出力スキーマ + few-shot 例(契約の提供のみ) | GSlidesSchema |
GSlidesA2A |
A2A Artifact/DataPart ⇄ schema coding、ストリームイベント写像 | + A2ACore |
GSlidesRequests |
batchUpdate write モデル(44 Request + Response の型安全ミラー) | GSlidesSchema |
GSlidesEdit |
ローカル batchUpdate 実行 reducer + 2 層バリデーション(preflight + atomic apply) | GSlidesRequests |
GSlidesRenderer |
SwiftUI レンダラ(16:9 キャンバス、EMU→pt、デッキテーマ → DS ColorPalette) | + DesignSystem |
GSlidesExport |
Presentation → PDF / PNG(ImageRenderer + CGContext) | GSlidesRenderer |
編集とバリデーション(GSlidesEdit)
編集エージェントは独自語彙ではなく 公式 batchUpdate リクエスト(Request 型のキュレートされた部分集合)を直接 emit する。適用は decode → preflight → atomic apply の 3 段で、本家 API のセマンティクスに忠実:
- 2 層構造: 下層(
Presentation.applying)は本家同様 all-or-nothing(「1 件でも不正ならバッチ全体が失敗し、何も適用されない」)。上層(PreflightValidator)は送信前に 全違反を一括収集し、エージェントが 1 パスで全部直せるようにする(サーバ往復を 1 回の判定に畳む)。 - 権威ある制約: バリデーション規則は
Sources/GSlidesSchema/Resources/Spec/constraints-catalog.yaml(一次仕様から逐語引用 + 出典 URL)が SSOT。objectId 正規表現/長さ/一意性、enum 網羅、oneof「ちょうど 1 つ」、field mask、テキスト範囲は (A) API が弾く制約として、ページ境界外への移動・退化変形(scale=0)は (B) API が弾かないため呼び出し側が担保する制約として検証する。 - エラーモデル: 拒否は
google.rpc.Status+BadRequest.FieldViolationを再現したBatchUpdateErrorで返す。field(リクエストへの dotted path)・reason(OBJECT_NOT_FOUND等の安定コード)・descriptionを持ち、promptFeedback(for:)で LLM 自己修正用に整形できる。 - 仕様の凍結と drift 検出: discovery doc は
scripts/fetch-discovery.shで取得し revision をピン。SpecProvenanceTestsが revision と検証が依存する逐語プローズの不変を保証する。詳細はResources/Spec/PROVENANCE.md。
テーマ
デッキの ColorScheme(master/layout/slide 継承)を DesignSystem の ColorPalette に射影する(DeckColorPalette)。
ACCENT1→primary、TEXT1/DARK1→onSurface、BACKGROUND1/LIGHT1→background のように DS のセマンティックスロットを埋め、
スライドの中身とクロームを同じ @Environment(\.colorPalette) で描く — 「Google Slides のテーマ忠実再現」と「デザインシステム統一」を両立する。
basePalette でデッキが定義しないスロットのフォールバックを差し替え可能。
使い方
// 受信側(A2A ストリーム → 表示)
var assembler = GSlidesArtifactAssembler()
for try await event in artifactEvents { // TaskArtifactUpdateEvent
try assembler.apply(event) // gslides 以外の artifact は自動スキップ
}
GSlidesDeckView(presentation: assembler.presentation!)
// 生成側(LLM 構造化出力 → 配信)
let schema = try GSlidesGenerationContract.jsonSchemaData() // モデルに渡す JSON Schema
let presentation = try GSlidesGenerationContract.presentation(from: llmOutput) // validate + expand
let event = try GSlidesArtifactCoding.envelopeEvent(
taskId: taskId, contextId: contextId, artifactId: "deck", presentation: presentation
)
スナップショット確認: GSLIDES_SNAPSHOT_DIR=/tmp/snap swift test --filter SnapshotDumpTests
ロードマップ
- M0 scaffold + vendored spec
- M1 GSlidesSchema: fixtures round-trip + enum parity
- M2 GSlidesLayout: md2googleslides ルール移植 parity
- M3 GSlidesAssembly: reducer(append / 全置換 / lastChunk / unknown layout first-class)
- M4 GSlidesA2A: イベント写像 + ワイヤ round-trip
- M5 GSlidesPrompt: validation sandwich
- M6 GSlidesRenderer: CLI ImageRenderer スモーク + スナップショットダンプ
- M7 デモ統合(A2AResearchDemo content 層)
License
MIT. Vendored assets and ported test rules from md2googleslides (Apache-2.0) — see NOTICE.