diff --git a/docs/design/stages/stage-01-style-governance.md b/docs/design/stages/stage-01-style-governance.md index 88b42eb8..1581ff1d 100644 --- a/docs/design/stages/stage-01-style-governance.md +++ b/docs/design/stages/stage-01-style-governance.md @@ -66,7 +66,7 @@ - チャート: `components.chart.palette` を優先し、系列ごとの `color_hex` がない場合に使用。 - 画像・テキストボックス: `components.image` / `components.textbox` の `fallback_box` を利用。 - レイアウト固有設定(`layouts.*.placements`)がある場合はアンカー解決時に上書き。 -- `pptx_generator/branding_extractor` は新スキーマへ対応させる(抽出結果を `theme` 相当へマッピング)。 +- `pptx_generator/template/branding_extractor` は新スキーマへ対応させる(抽出結果を `theme` 相当へマッピング)。 ## テスト計画 - `tests/test_settings.py`: 新スキーマ読み込みの正常系/異常系テストを更新。 diff --git a/docs/notes/20250215-rm081-font-capacity-discussion.md b/docs/notes/20250215-rm081-font-capacity-discussion.md index 67ccbbb0..81bf5a2c 100644 --- a/docs/notes/20250215-rm081-font-capacity-discussion.md +++ b/docs/notes/20250215-rm081-font-capacity-discussion.md @@ -29,7 +29,7 @@ Plan(承認待ち): - 既存レコード生成テストを更新し、差分確認用に追加の期待値を組み込む。 4. JobSpec 変換・テスト・サンプル更新 - - `src/pptx_generator/spec_loader.py` と `src/pptx_generator/generate_ready.py` で `text_capacity` を取り扱うようにし、Scaffold→JobSpec 変換時に SlideTextbox へ伝播。 + - `src/pptx_generator/template/spec_loader.py` と `src/pptx_generator/pipeline/generate_ready.py` で `text_capacity` を取り扱うようにし、Scaffold→JobSpec 変換時に SlideTextbox へ伝播。 - `tests/template_audit/test_template_extractor_jobspec_output.py` や `tests/layout_validation/*` など関連テスト、サンプル JSON を更新。 - ドキュメント(requirements/design/roadmap/ToDo メモ)に実装結果・利用方法を反映。 diff --git a/docs/notes/20251105-jobspec-scaffold-validation.md b/docs/notes/20251105-jobspec-scaffold-validation.md index e56a9f06..bce688f8 100644 --- a/docs/notes/20251105-jobspec-scaffold-validation.md +++ b/docs/notes/20251105-jobspec-scaffold-validation.md @@ -33,6 +33,6 @@ feat/047-draft-structuring での調査結果 2. もしくはテンプレ抽出成果物と compose 入力スキーマ統合に向けたロードマップ項目の起票。 ## 2025-11-08 更新 -- `pptx_generator.spec_loader.load_jobspec_from_path` を導入し、テンプレ抽出 `jobspec.json` を読み込んだ際に `JobSpecScaffold` を `JobSpec` へ自動変換する処理を追加。 +- `pptx_generator.template.load_jobspec_from_path` を導入し、テンプレ抽出 `jobspec.json` を読み込んだ際に `JobSpecScaffold` を `JobSpec` へ自動変換する処理を追加。 - 変換時はテンプレプレースホルダから `Slide.textboxes` を生成し、タイトル/サブタイトルの初期値や非テキスト要素の要約を `notes` に残す。 - CLI (`pptx compose` / `pptx mapping`) は従来どおり `_load_jobspec` を経由するため、テンプレ抽出直後の `jobspec.json` でもバリデーションエラーなく実行できる。 diff --git a/docs/todo/20260107-rm098-accuracy-improvement.md b/docs/todo/20260107-rm098-accuracy-improvement.md index 329b96ae..4bfea185 100644 --- a/docs/todo/20260107-rm098-accuracy-improvement.md +++ b/docs/todo/20260107-rm098-accuracy-improvement.md @@ -2,7 +2,7 @@ 目的: 動的・静的テンプレート対応を含む精度改善 roadmap_item: RM-098 精度改善 関連ブランチ: feat/rm098-accuracy-improvement -関連Issue: +関連Issue: #527 期限: --- diff --git a/docs/todo/archive/20251102-rm049-pptx-gen-scope.md b/docs/todo/archive/20251102-rm049-pptx-gen-scope.md index 58a5849b..08a36998 100644 --- a/docs/todo/archive/20251102-rm049-pptx-gen-scope.md +++ b/docs/todo/archive/20251102-rm049-pptx-gen-scope.md @@ -154,7 +154,7 @@ roadmap_item: RM-049 pptx gen スコープ最適化 ## メモ **主変更点** - `src/pptx_generator/cli.py`: `pptx gen` を `generate_ready.json` 専用入力へ統一し、テンプレートパス欠落時にエラーを返す。`pptx mapping` は `--template` 指定を必須化し、監査メタ `mapping_meta` に `template_path` を確実に記録。 -- `src/pptx_generator/pipeline/mapping.py`、`src/pptx_generator/generate_ready.py`: `GenerateReadyDocument.meta.template_path` を埋め込み、`mapping_meta` と監査ログにテンプレート情報を反映。 +- `src/pptx_generator/pipeline/mapping.py`、`src/pptx_generator/pipeline/generate_ready.py`: `GenerateReadyDocument.meta.template_path` を埋め込み、`mapping_meta` と監査ログにテンプレート情報を反映。 - `tests/test_cli_integration.py` / `tests/test_cli_cheatsheet_flow.py` / `tests/test_mapping_step.py`: generate_ready 専用フローに合わせてテンプレート必須化と新エラーハンドリングを検証。 - README・`docs/design/cli/cli-command-reference.md`・`docs/runbooks/story-outline-ops.md` ほか関連ドキュメントを更新し、`pptx gen` の入力仕様と `--template` 必須化を明記。 - `docs/notes/20251109-generate-ready-meta.md`: Prepare 正規化後も generate_ready メタ方針を維持する旨を追記。 diff --git a/docs/todo/archive/20251104-rm047-draft-structuring.md b/docs/todo/archive/20251104-rm047-draft-structuring.md index e612a665..96eca0df 100644 --- a/docs/todo/archive/20251104-rm047-draft-structuring.md +++ b/docs/todo/archive/20251104-rm047-draft-structuring.md @@ -18,7 +18,7 @@ roadmap_item: RM-047 テンプレ統合構成生成AI連携 - `docs/roadmap/roadmap.md` の RM-047 セクションを進行中へ更新し、新設ドキュメントへのリンクを追加する。 3. **モデル・ユーティリティ追加** - `src/pptx_generator/models.py` に `GenerateReadyDocument` 系モデルを追加し、旧 `Draft*`/`RenderingReady` 系に依存しない構造へ刷新する。 - - `src/pptx_generator/generate_ready.py` を新規実装し、`generate_ready_to_jobspec` など Stage5 で必要な変換ユーティリティを提供する。 + - `src/pptx_generator/pipeline/generate_ready.py` を新規実装し、`generate_ready_to_jobspec` など Stage5 で必要な変換ユーティリティを提供する。 4. **stage 4 パイプライン実装** - `pipeline/draft_structuring.py` を `prepare_card.json` と `jobspec.json` の突合前提に書き換え、カード単位の割当結果を `GenerateReadyDocument` へ連携できるようにする。 - `pipeline/prepare_normalization.py`・`pipeline/mapping.py` を含む CLI パイプラインを全面刷新し、`draft_*`/`rendering_ready` 出力を廃止。`generate_ready.json` を唯一の後続入力として扱う。 @@ -34,7 +34,7 @@ roadmap_item: RM-047 テンプレ統合構成生成AI連携 8. **フォローアップ** - stage 2 から追加で必要となった情報があれば docs/notes と ToDo メモに記録し、ユーザーへ報告する。 - スコープ: stage 4 全体を `generate_ready` 基盤へ全面置換し、既存 `draft_*` および `rendering_ready` 系の入出力は廃止する。後方互換の考慮は不要、完全新規置換で進める。 - - 想定影響ファイル: `docs/design/stages/stage-03-compose.md`、`docs/design/design.md`、`docs/requirements/stages/stage-03-compose.md`、`docs/roadmap/roadmap.md`、`src/pptx_generator/models.py`、`src/pptx_generator/cli.py`、`src/pptx_generator/generate_ready.py`(新規)、`src/pptx_generator/pipeline/prepare_normalization.py`、`src/pptx_generator/pipeline/draft_structuring.py`、`src/pptx_generator/pipeline/mapping.py`、該当テストファイル。 + - 想定影響ファイル: `docs/design/stages/stage-03-compose.md`、`docs/design/design.md`、`docs/requirements/stages/stage-03-compose.md`、`docs/roadmap/roadmap.md`、`src/pptx_generator/models.py`、`src/pptx_generator/cli.py`、`src/pptx_generator/pipeline/generate_ready.py`(新規)、`src/pptx_generator/pipeline/prepare_normalization.py`、`src/pptx_generator/pipeline/draft_structuring.py`、`src/pptx_generator/pipeline/mapping.py`、該当テストファイル。 - リスク: PrepareCard 仕様変更の波及、AI 推薦精度の不確実性による再調整、CLI 引数廃止に伴うドキュメント更新漏れ。 - テスト方針: 上記テスト更新に加え、`uv run --extra dev pytest` を実行して全体整合を確認する。 - ロールバック方法: 変更・追加した Markdown および Python ファイルを個別に戻すことで復旧可能。 diff --git a/docs/todo/archive/20251124-rm081-text-capacity.md b/docs/todo/archive/20251124-rm081-text-capacity.md index a08163c5..ede5080d 100644 --- a/docs/todo/archive/20251124-rm081-text-capacity.md +++ b/docs/todo/archive/20251124-rm081-text-capacity.md @@ -28,7 +28,7 @@ roadmap_item: RM-081 文字数許容量算出とスキーマ反映 - Renderer (`src/pptx_generator/pipeline/renderer.py`): タイトル・本文・箇条書きのフォント適用、段落スタイル、テーブル/チャートの配色、アンカー未指定時のフォールバック座標を `TemplateStyle` のデフォルト値から解決している。 - Analyzer (`_build_analyzer_options`)・Refiner (`_build_refiner_options`): `TemplateStyle` の body フォントおよびカラーを既定値として取り込み、フォントサイズしきい値やカラー調整の初期値を決定している。 - 設定ファイル・テスト: `settings.BrandingConfig` はテンプレ抽出結果を `TemplateStyle` に変換するための互換レイヤとして残存。ユニットテスト(`tests/config/test_settings_loading.py`)は引き続き旧スキーマ検証を担う。 - - テンプレートスタイル抽出: `src/pptx_generator/template_style.py` で `BrandingExtractionResult` を `TemplateStyle`/アーティファクトへ変換する。今後は `branding_extractor` 依存を段階的に薄め、テンプレ由来メタに一本化する。 + - テンプレートスタイル抽出: `src/pptx_generator/template/template_style.py` で `BrandingExtractionResult` を `TemplateStyle`/アーティファクトへ変換する。今後は `template/branding_extractor` 依存を段階的に薄め、テンプレ由来メタに一本化する。 - 移行論点: - Slide.title / subtitle には現状フォント情報が載らないため、テンプレ抽出時に `SlideTextbox` へ転記するか `generate_ready.meta` 側でヘッダ用スタイルを保持する仕組みが必要。 - 監査ログ (`audit_log.json`) では `template_style.source` にテンプレパスと抽出エラーを記録している。BrandingConfig 廃止後もテンプレ由来スタイルと抽出エラー情報を保持できるよう新メタ形式を用意する。 diff --git a/docs/todo/archive/20251206-rm058-remove-chapter-templates.md b/docs/todo/archive/20251206-rm058-remove-chapter-templates.md index 37160fa5..7b30b05f 100644 --- a/docs/todo/archive/20251206-rm058-remove-chapter-templates.md +++ b/docs/todo/archive/20251206-rm058-remove-chapter-templates.md @@ -13,7 +13,7 @@ roadmap_item: RM-058 プレペア骨子内製化 - 対象整理(スコープ、対象ファイル、前提): 章テンプレート資産 (`config/chapter_templates/`)、CLI `outline`/`compose` のテンプレ関連オプション、Draft structuring / layout 評価のテンプレ依存ロジック、関連テスト・ドキュメントを削除または更新する。 - ドキュメント/コード修正方針: CLI オプションとハンドラロジックを撤廃し、テンプレ適合率に依存するメタ項目を整備し直す。対応する単体テスト・統合テストを更新し、ドキュメントの記述も改訂する。 - 確認・共有方法(レビュー、ToDo 更新など): ToDo に進捗を記録し、作業完了後にドラフト PR でまとめて共有する。 - - 想定影響ファイル: `config/chapter_templates/**/*`, `src/pptx_generator/cli_commands/outline.py`, `compose.py`, `cli_handlers/outline.py`, `compose.py`, `draft_intel.py`, draft structuring系 (`pipeline/draft_structuring/*`), テスト群, 関連 docs。 + - 想定影響ファイル: `config/chapter_templates/**/*`, `src/pptx_generator/cli_commands/outline.py`, `compose.py`, `cli_handlers/outline.py`, `compose.py`, `draft/draft_intel.py`, draft structuring系 (`pipeline/draft_structuring/*`), テスト群, 関連 docs。 - リスク: 章テンプレ基盤を利用しているワークフローがあれば後方互換がなくなる。`layout_score_detail` などテンプレ由来のログ項目の整理漏れに注意。 - テスト方針: `uv run --extra dev pytest` 全体実行。特に `tests/cli/test_cli_outline_generation.py` など章テンプレ依存テストの更新確認。 - ロールバック方法: 章テンプレ削除コミットを revert し、`config/chapter_templates` と CLI オプションを復旧する。 diff --git a/samples/input/sample_spec.md b/samples/input/sample_spec.md index 0d45603e..265261ac 100644 --- a/samples/input/sample_spec.md +++ b/samples/input/sample_spec.md @@ -2048,14 +2048,16 @@ async def generate_pptx(spec: GenerateRequest): ### Python API 利用例 ```python +from pathlib import Path + from pptx_generator.pipeline.renderer import Renderer -from pptx_generator.spec_loader import load_spec +from pptx_generator.template import load_jobspec_from_path # JSON 仕様を読み込み -spec = load_spec("samples/json/sample_spec.json") +spec = load_jobspec_from_path(Path("samples/json/sample_spec.json")) # テンプレートを指定してレンダリング -renderer = Renderer(template_path="samples/templates/templates.pptx") +renderer = Renderer(template_path=Path("samples/templates/templates.pptx")) prs = renderer.render(spec) # PPTX を保存 diff --git a/scripts/branding_extract.py b/scripts/branding_extract.py index f3869e54..c0ff3c37 100644 --- a/scripts/branding_extract.py +++ b/scripts/branding_extract.py @@ -7,10 +7,7 @@ import sys from pathlib import Path -from pptx_generator.branding_extractor import ( - BrandingExtractionError, - extract_branding_config, -) +from pptx_generator.template import BrandingExtractionError, extract_branding_config def parse_args() -> argparse.Namespace: diff --git a/src/pptx_generator/cli_handlers/common.py b/src/pptx_generator/cli_handlers/common.py index a9b3b1ae..5a925cad 100644 --- a/src/pptx_generator/cli_handlers/common.py +++ b/src/pptx_generator/cli_handlers/common.py @@ -9,11 +9,11 @@ from pydantic import BaseModel -from pptx_generator.config_manager import ConfigManager +from pptx_generator.config import ConfigManager from pptx_generator.llm import log_provider_resolution, resolve_llm_provider from pptx_generator.logging import LOG_FORMAT, ensure_rotating_file_handler, ensure_stream_handler from pptx_generator.models import JobSpec -from pptx_generator.spec_loader import load_jobspec_from_path +from pptx_generator.template import load_jobspec_from_path logger = logging.getLogger(__name__) diff --git a/src/pptx_generator/cli_handlers/compose.py b/src/pptx_generator/cli_handlers/compose.py index a512ab86..d2ec4079 100644 --- a/src/pptx_generator/cli_handlers/compose.py +++ b/src/pptx_generator/cli_handlers/compose.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Optional -from pptx_generator.config_manager import ConfigManager +from pptx_generator.config import ConfigManager from pptx_generator.pipeline import ( DraftStructuringError, DraftStructuringOptions, diff --git a/src/pptx_generator/cli_handlers/mapping.py b/src/pptx_generator/cli_handlers/mapping.py index b0acd363..9fcab8fc 100644 --- a/src/pptx_generator/cli_handlers/mapping.py +++ b/src/pptx_generator/cli_handlers/mapping.py @@ -10,8 +10,8 @@ import click -from pptx_generator.config_manager import ConfigManager, ResolvedConfig -from pptx_generator.generate_ready import generate_ready_to_jobspec +from pptx_generator.config import ConfigManager, ResolvedConfig +from pptx_generator.pipeline.generate_ready import generate_ready_to_jobspec from pptx_generator.models import ( GenerateReadyDocument, JobMeta, @@ -109,7 +109,7 @@ def _should_enforce_layouts() -> bool: def prepare_template_style(template: Path) -> TemplateStylePayload: - from pptx_generator.template_style import extract_template_style + from pptx_generator.template import extract_template_style style, artifact = extract_template_style(template) if artifact.get("source", {}).get("type") == "default": diff --git a/src/pptx_generator/cli_handlers/prepare_static.py b/src/pptx_generator/cli_handlers/prepare_static.py index 2daa5a25..c8c9ac25 100644 --- a/src/pptx_generator/cli_handlers/prepare_static.py +++ b/src/pptx_generator/cli_handlers/prepare_static.py @@ -20,7 +20,7 @@ from pptx_generator.content_import import ContentImportService from pptx_generator.prepare import PrepareDocument from pptx_generator.prepare.source import PrepareSourceDocument -from pptx_generator.spec_loader import load_jobspec_from_path +from pptx_generator.template import load_jobspec_from_path from .prepare_errors import PrepareCommandError diff --git a/src/pptx_generator/cli_handlers/rendering.py b/src/pptx_generator/cli_handlers/rendering.py index 64295a5c..403652cd 100644 --- a/src/pptx_generator/cli_handlers/rendering.py +++ b/src/pptx_generator/cli_handlers/rendering.py @@ -10,7 +10,7 @@ import click -from pptx_generator.generate_ready import generate_ready_to_jobspec +from pptx_generator.pipeline.generate_ready import generate_ready_to_jobspec from pptx_generator.models import GenerateReadyDocument, TemplateStyle from pptx_generator.pipeline import ( AnalyzerOptions, @@ -35,7 +35,7 @@ from pptx_generator.settings import RulesConfig from pptx_generator.settings.loader import load_rules_config from pptx_generator.settings.paths import find_config_path -from pptx_generator.template_style import extract_template_style +from pptx_generator.template import extract_template_style from .trace_utils import record_stage_trace logger = logging.getLogger(__name__) diff --git a/src/pptx_generator/cli_handlers/template_extraction.py b/src/pptx_generator/cli_handlers/template_extraction.py index 344dd7b5..90a130bc 100644 --- a/src/pptx_generator/cli_handlers/template_extraction.py +++ b/src/pptx_generator/cli_handlers/template_extraction.py @@ -12,7 +12,7 @@ from pptx import Presentation from pptx.enum.shapes import MSO_SHAPE_TYPE, PP_PLACEHOLDER -from pptx_generator.branding_extractor import extract_branding_config +from pptx_generator.template import extract_branding_config from pptx_generator.cli_handlers.prepare import ( PROMPT_TEMPLATE_FILENAME_PATTERN, PROMPT_USER_SECTION_END, diff --git a/src/pptx_generator/cli_handlers/template_release.py b/src/pptx_generator/cli_handlers/template_release.py index 8b72d675..98c4e0d8 100644 --- a/src/pptx_generator/cli_handlers/template_release.py +++ b/src/pptx_generator/cli_handlers/template_release.py @@ -29,7 +29,7 @@ build_template_release, load_template_release, ) -from pptx_generator.template_style import extract_template_style +from pptx_generator.template import extract_template_style from pptx_generator.models import ( TemplateRelease, TemplateReleaseDiagnostics, diff --git a/src/pptx_generator/config/__init__.py b/src/pptx_generator/config/__init__.py index 6a6c0dff..58e73187 100644 --- a/src/pptx_generator/config/__init__.py +++ b/src/pptx_generator/config/__init__.py @@ -1,5 +1,7 @@ -"""Default configuration assets bundled with the package.""" +"""設定関連のエントリーポイント。""" from __future__ import annotations -__all__ = [] +from .config_manager import ConfigManager, ResolvedConfig + +__all__ = ["ConfigManager", "ResolvedConfig"] diff --git a/src/pptx_generator/config_manager.py b/src/pptx_generator/config/config_manager.py similarity index 100% rename from src/pptx_generator/config_manager.py rename to src/pptx_generator/config/config_manager.py diff --git a/src/pptx_generator/draft/__init__.py b/src/pptx_generator/draft/__init__.py new file mode 100644 index 00000000..de5abf94 --- /dev/null +++ b/src/pptx_generator/draft/__init__.py @@ -0,0 +1,45 @@ +"""ドラフト関連ユーティリティ。""" + +from __future__ import annotations + +from .draft_intel import ( + ChapterTemplate, + ChapterTemplateEvaluation, + ChapterTemplateSection, + ReturnReasonTemplate, + clamp_score_detail, + compute_analyzer_support, + evaluate_chapter_template, + find_chapter_template_path, + find_template_by_structure, + load_analysis_summary, + load_chapter_template, + load_return_reasons, + summarize_analyzer_counts, +) +from .draft_recommender import ( + CardLayoutRecommender, + CardLayoutRecommenderConfig, + LayoutProfile, + RecommendationResult, +) + +__all__ = [ + "CardLayoutRecommender", + "CardLayoutRecommenderConfig", + "ChapterTemplate", + "ChapterTemplateEvaluation", + "ChapterTemplateSection", + "LayoutProfile", + "RecommendationResult", + "ReturnReasonTemplate", + "clamp_score_detail", + "compute_analyzer_support", + "evaluate_chapter_template", + "find_chapter_template_path", + "find_template_by_structure", + "load_analysis_summary", + "load_chapter_template", + "load_return_reasons", + "summarize_analyzer_counts", +] diff --git a/src/pptx_generator/draft_intel.py b/src/pptx_generator/draft/draft_intel.py similarity index 99% rename from src/pptx_generator/draft_intel.py rename to src/pptx_generator/draft/draft_intel.py index be6cdf4b..91eff651 100644 --- a/src/pptx_generator/draft_intel.py +++ b/src/pptx_generator/draft/draft_intel.py @@ -8,8 +8,7 @@ from pathlib import Path from typing import Iterable, Mapping -from .models import (DraftAnalyzerSummary, DraftLayoutScoreDetail, - DraftTemplateMismatch) +from ..models import DraftAnalyzerSummary, DraftLayoutScoreDetail, DraftTemplateMismatch logger = logging.getLogger(__name__) diff --git a/src/pptx_generator/draft_recommender.py b/src/pptx_generator/draft/draft_recommender.py similarity index 97% rename from src/pptx_generator/draft_recommender.py rename to src/pptx_generator/draft/draft_recommender.py index 06f36359..63c77fbb 100644 --- a/src/pptx_generator/draft_recommender.py +++ b/src/pptx_generator/draft/draft_recommender.py @@ -8,15 +8,22 @@ from typing import Iterable, Sequence, Tuple from .draft_intel import clamp_score_detail, compute_analyzer_support -from .layout_ai import (LayoutAIPolicy, LayoutAIRequest, LayoutAIResponse, - create_layout_ai_client, load_layout_policy_set) -from .layout_ai.client import LayoutAIClient, LayoutAIClientConfigurationError -from .layout_ai.policy import LayoutAIPolicyError, LayoutAIPolicySet -from .models import (ContentSlide, DraftAnalyzerSummary, DraftLayoutCandidate, - DraftLayoutScoreDetail) -from .utils.usage_tags import (CANONICAL_USAGE_TAGS, get_usage_tag_catalog, - normalize_usage_tag_value, - normalize_usage_tags_with_unknown) +from ..layout_ai import ( + LayoutAIPolicy, + LayoutAIRequest, + LayoutAIResponse, + create_layout_ai_client, + load_layout_policy_set, +) +from ..layout_ai.client import LayoutAIClient, LayoutAIClientConfigurationError +from ..layout_ai.policy import LayoutAIPolicyError, LayoutAIPolicySet +from ..models import ContentSlide, DraftAnalyzerSummary, DraftLayoutCandidate, DraftLayoutScoreDetail +from ..utils.usage_tags import ( + CANONICAL_USAGE_TAGS, + get_usage_tag_catalog, + normalize_usage_tag_value, + normalize_usage_tags_with_unknown, +) logger = logging.getLogger(__name__) diff --git a/src/pptx_generator/pipeline/base.py b/src/pptx_generator/pipeline/base.py index 62e5c0d2..174e7228 100644 --- a/src/pptx_generator/pipeline/base.py +++ b/src/pptx_generator/pipeline/base.py @@ -9,7 +9,7 @@ from typing import Any, Iterable, Iterator, MutableMapping, Protocol from uuid import uuid4 -from ..config_manager import ResolvedConfig +from ..config import ResolvedConfig from ..models import JobSpec from ..runtime.job_context import get_current_job from ..logging import set_current_stage diff --git a/src/pptx_generator/pipeline/draft_structuring/dynamic_flow.py b/src/pptx_generator/pipeline/draft_structuring/dynamic_flow.py index 164786da..1a5bdff4 100644 --- a/src/pptx_generator/pipeline/draft_structuring/dynamic_flow.py +++ b/src/pptx_generator/pipeline/draft_structuring/dynamic_flow.py @@ -4,8 +4,8 @@ from collections import Counter, defaultdict from typing import Any, Mapping, Sequence -from ...draft_intel import summarize_analyzer_counts -from ...draft_recommender import CardLayoutRecommender, LayoutProfile +from ...draft.draft_intel import summarize_analyzer_counts +from ...draft.draft_recommender import CardLayoutRecommender, LayoutProfile from ...models import ( ContentApprovalDocument, ContentSlide, diff --git a/src/pptx_generator/pipeline/draft_structuring/dynamic_runtime.py b/src/pptx_generator/pipeline/draft_structuring/dynamic_runtime.py index d743bf5c..27023be4 100644 --- a/src/pptx_generator/pipeline/draft_structuring/dynamic_runtime.py +++ b/src/pptx_generator/pipeline/draft_structuring/dynamic_runtime.py @@ -7,7 +7,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Any, Dict, List, Tuple -from ...draft_intel import load_analysis_summary +from ...draft.draft_intel import load_analysis_summary from ...prepare.models import PrepareDocument, PrepareGenerationMeta from ...models import ( ContentApprovalDocument, @@ -17,7 +17,7 @@ ) from ..base import PipelineContext from ..slide_alignment import SlideIdAligner, SlideIdAlignerOptions -from ...draft_recommender import CardLayoutRecommender, CardLayoutRecommenderConfig, LayoutProfile +from ...draft.draft_recommender import CardLayoutRecommender, CardLayoutRecommenderConfig, LayoutProfile from ...settings.ai_policy import resolve_layout_ai_policy_path from ...api.draft_store import BoardAlreadyExistsError, DraftStore from .errors import DraftStructuringError diff --git a/src/pptx_generator/pipeline/draft_structuring/layout_loader.py b/src/pptx_generator/pipeline/draft_structuring/layout_loader.py index 3484de09..d0031118 100644 --- a/src/pptx_generator/pipeline/draft_structuring/layout_loader.py +++ b/src/pptx_generator/pipeline/draft_structuring/layout_loader.py @@ -8,7 +8,7 @@ from pathlib import Path from typing import Any, Mapping, Sequence -from ...draft_recommender import LayoutProfile +from ...draft.draft_recommender import LayoutProfile from ...utils.usage_tags import normalize_usage_tags from ..table_anchor import normalize_placeholders from .errors import DraftStructuringError diff --git a/src/pptx_generator/pipeline/draft_structuring/slide_elements.py b/src/pptx_generator/pipeline/draft_structuring/slide_elements.py index 3e4ec753..e69b8409 100644 --- a/src/pptx_generator/pipeline/draft_structuring/slide_elements.py +++ b/src/pptx_generator/pipeline/draft_structuring/slide_elements.py @@ -7,7 +7,7 @@ from ...models import ContentElements, ContentSlide, Slide, TemplateBlueprintSlot from ...prepare.models import PrepareCard -from ...draft_recommender import LayoutProfile +from ...draft.draft_recommender import LayoutProfile from ..table_anchor import build_table_payload, is_table_payload, resolve_table_anchor logger = logging.getLogger(__name__) diff --git a/src/pptx_generator/pipeline/draft_structuring/static_runtime.py b/src/pptx_generator/pipeline/draft_structuring/static_runtime.py index 70cd6c9e..222c2d4e 100644 --- a/src/pptx_generator/pipeline/draft_structuring/static_runtime.py +++ b/src/pptx_generator/pipeline/draft_structuring/static_runtime.py @@ -33,7 +33,7 @@ Slide, ) from ..base import PipelineContext -from ...draft_recommender import LayoutProfile +from ...draft.draft_recommender import LayoutProfile from ...api.draft_store import DraftStore, BoardAlreadyExistsError from .errors import DraftStructuringError from .types import DraftStructuringOptions, StaticArtifacts, card_slot_fulfilled, card_slot_id diff --git a/src/pptx_generator/pipeline/draft_structuring/step.py b/src/pptx_generator/pipeline/draft_structuring/step.py index 6810ea3a..54df87cf 100644 --- a/src/pptx_generator/pipeline/draft_structuring/step.py +++ b/src/pptx_generator/pipeline/draft_structuring/step.py @@ -36,7 +36,7 @@ Slide, TemplateSpec, ) -from ...draft_recommender import CardLayoutRecommender, LayoutProfile +from ...draft.draft_recommender import CardLayoutRecommender, LayoutProfile from ...api.draft_store import DraftStore, BoardAlreadyExistsError from ..base import PipelineContext, PipelineStage from .errors import DraftStructuringError diff --git a/src/pptx_generator/generate_ready.py b/src/pptx_generator/pipeline/generate_ready.py similarity index 96% rename from src/pptx_generator/generate_ready.py rename to src/pptx_generator/pipeline/generate_ready.py index 866a0eb8..99455c78 100644 --- a/src/pptx_generator/generate_ready.py +++ b/src/pptx_generator/pipeline/generate_ready.py @@ -8,11 +8,27 @@ from pydantic import ValidationError -from .models import (ChartOptions, ChartSeries, FontSpec, GenerateReadyDocument, - GenerateReadySlide, JobAuth, JobMeta, JobSpec, Slide, - SlideBullet, SlideBulletGroup, SlideChart, SlideImage, - SlideTable, SlideTextbox, TextCapacity, TextFramePadding, - TextboxParagraph, TextboxPosition) +from ..models import ( + ChartOptions, + ChartSeries, + FontSpec, + GenerateReadyDocument, + GenerateReadySlide, + JobAuth, + JobMeta, + JobSpec, + Slide, + SlideBullet, + SlideBulletGroup, + SlideChart, + SlideImage, + SlideTable, + SlideTextbox, + TextCapacity, + TextFramePadding, + TextboxParagraph, + TextboxPosition, +) def generate_ready_to_jobspec(document: GenerateReadyDocument) -> JobSpec: diff --git a/src/pptx_generator/pipeline/template_extractor/step.py b/src/pptx_generator/pipeline/template_extractor/step.py index 9ca293bd..a58014fc 100644 --- a/src/pptx_generator/pipeline/template_extractor/step.py +++ b/src/pptx_generator/pipeline/template_extractor/step.py @@ -23,7 +23,7 @@ generate_layout_description, summarize_placeholders, ) -from ...branding_extractor import BrandingExtractionError, extract_branding_config +from ...template.branding_extractor import BrandingExtractionError, extract_branding_config from ...models import FontSpec, LayoutInfo, ShapeInfo, TemplateBlueprint, TemplateSpec logger = logging.getLogger(__name__) diff --git a/src/pptx_generator/pipeline/trace.py b/src/pptx_generator/pipeline/trace.py index e5932538..e6104193 100644 --- a/src/pptx_generator/pipeline/trace.py +++ b/src/pptx_generator/pipeline/trace.py @@ -5,7 +5,7 @@ from typing import Any from .base import PipelineContext, StageResult -from ..config_manager import ResolvedConfig +from ..config import ResolvedConfig def _serialize_stage_result(result: StageResult) -> dict[str, Any]: diff --git a/src/pptx_generator/template/__init__.py b/src/pptx_generator/template/__init__.py new file mode 100644 index 00000000..76f0728d --- /dev/null +++ b/src/pptx_generator/template/__init__.py @@ -0,0 +1,23 @@ +"""テンプレート関連のユーティリティ集。""" + +from __future__ import annotations + +from .branding_extractor import ( + BrandingExtractionError, + BrandingExtractionResult, + SCHEME_COLOR_TAG, + extract_branding_config, +) +from .spec_loader import convert_scaffold_to_jobspec, load_jobspec_from_path +from .template_style import extract_template_style, template_style_from_branding + +__all__ = [ + "BrandingExtractionError", + "BrandingExtractionResult", + "SCHEME_COLOR_TAG", + "convert_scaffold_to_jobspec", + "extract_branding_config", + "extract_template_style", + "load_jobspec_from_path", + "template_style_from_branding", +] diff --git a/src/pptx_generator/branding_extractor.py b/src/pptx_generator/template/branding_extractor.py similarity index 99% rename from src/pptx_generator/branding_extractor.py rename to src/pptx_generator/template/branding_extractor.py index 4e1414ec..7968e5c1 100644 --- a/src/pptx_generator/branding_extractor.py +++ b/src/pptx_generator/template/branding_extractor.py @@ -9,7 +9,7 @@ from zipfile import ZipFile from xml.etree import ElementTree as ET -from .settings import BrandingConfig, BrandingFont, BoxSpec, ParagraphStyle +from ..settings import BrandingConfig, BrandingFont, BoxSpec, ParagraphStyle NS = { "a": "http://schemas.openxmlformats.org/drawingml/2006/main", diff --git a/src/pptx_generator/spec_loader.py b/src/pptx_generator/template/spec_loader.py similarity index 99% rename from src/pptx_generator/spec_loader.py rename to src/pptx_generator/template/spec_loader.py index 14f0c8e0..eea581fc 100644 --- a/src/pptx_generator/spec_loader.py +++ b/src/pptx_generator/template/spec_loader.py @@ -9,7 +9,7 @@ from pydantic import ValidationError -from .models import ( +from ..models import ( JobAuth, JobMeta, JobSpec, diff --git a/src/pptx_generator/template_style.py b/src/pptx_generator/template/template_style.py similarity index 97% rename from src/pptx_generator/template_style.py rename to src/pptx_generator/template/template_style.py index 34cf5b8d..5215cf71 100644 --- a/src/pptx_generator/template_style.py +++ b/src/pptx_generator/template/template_style.py @@ -6,7 +6,7 @@ from pathlib import Path from .branding_extractor import BrandingExtractionError, extract_branding_config -from .models import ( +from ..models import ( FontSpec, TemplateChartDefaults, TemplateColorPalette, @@ -17,7 +17,7 @@ TextboxParagraph, TextboxPosition, ) -from .settings import BrandingConfig, BrandingFont, BoxSpec, ParagraphStyle +from ..settings import BrandingConfig, BrandingFont, BoxSpec, ParagraphStyle logger = logging.getLogger(__name__) diff --git a/tests/branding/test_branding_extractor_scheme_tag.py b/tests/branding/test_branding_extractor_scheme_tag.py index fef4baa5..57d3da9e 100644 --- a/tests/branding/test_branding_extractor_scheme_tag.py +++ b/tests/branding/test_branding_extractor_scheme_tag.py @@ -2,7 +2,11 @@ import xml.etree.ElementTree as ET -from pptx_generator.branding_extractor import SCHEME_COLOR_TAG, _color_from_def, _resolve_background_color +from pptx_generator.template.branding_extractor import ( + SCHEME_COLOR_TAG, + _color_from_def, + _resolve_background_color, +) NS = { "a": "http://schemas.openxmlformats.org/drawingml/2006/main", diff --git a/tests/branding/test_branding_extractor_usage.py b/tests/branding/test_branding_extractor_usage.py index a93b3c99..1df98871 100644 --- a/tests/branding/test_branding_extractor_usage.py +++ b/tests/branding/test_branding_extractor_usage.py @@ -4,7 +4,7 @@ import pytest -from pptx_generator.branding_extractor import ( +from pptx_generator.template import ( BrandingExtractionError, extract_branding_config, ) diff --git a/tests/cli_handlers/test_common_path_resolution.py b/tests/cli_handlers/test_common_path_resolution.py index 2eb12e18..83ca72f3 100644 --- a/tests/cli_handlers/test_common_path_resolution.py +++ b/tests/cli_handlers/test_common_path_resolution.py @@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict from pptx_generator.cli_handlers import common -from pptx_generator.config_manager import ConfigManager +from pptx_generator.config import ConfigManager class _DummySpec: diff --git a/tests/draft_intel/test_draft_intel_refactor.py b/tests/draft_intel/test_draft_intel_refactor.py index a048fc9e..d3c8961d 100644 --- a/tests/draft_intel/test_draft_intel_refactor.py +++ b/tests/draft_intel/test_draft_intel_refactor.py @@ -3,7 +3,7 @@ import json from pathlib import Path -from pptx_generator.draft_intel import ( +from pptx_generator.draft import ( ChapterTemplate, ChapterTemplateSection, evaluate_chapter_template, diff --git a/tests/draft_intel/test_return_reasons.py b/tests/draft_intel/test_return_reasons.py index 73fa45bc..d4209392 100644 --- a/tests/draft_intel/test_return_reasons.py +++ b/tests/draft_intel/test_return_reasons.py @@ -2,14 +2,13 @@ from pathlib import Path -from pptx_generator import draft_intel -from pptx_generator.draft_intel import ReturnReasonTemplate +from pptx_generator.draft import ReturnReasonTemplate, load_return_reasons def test_load_return_reasons_returns_builtin_templates(tmp_path: Path) -> None: dummy_path = tmp_path / "return_reasons.json" - reasons = draft_intel.load_return_reasons(dummy_path) + reasons = load_return_reasons(dummy_path) assert isinstance(reasons, tuple) assert [item.code for item in reasons] == [ diff --git a/tests/generate_ready/test_generate_ready_utils.py b/tests/generate_ready/test_generate_ready_utils.py index 72e5d0b3..186fa8ac 100644 --- a/tests/generate_ready/test_generate_ready_utils.py +++ b/tests/generate_ready/test_generate_ready_utils.py @@ -7,7 +7,7 @@ from pptx_generator.models import (JobAuth, JobMeta, MappingSlideMeta, GenerateReadyDocument, GenerateReadyMeta, GenerateReadySlide) -from pptx_generator.generate_ready import generate_ready_to_jobspec +from pptx_generator.pipeline.generate_ready import generate_ready_to_jobspec def test_generate_ready_to_jobspec_conversion() -> None: diff --git a/tests/imports/test_module_imports.py b/tests/imports/test_module_imports.py new file mode 100644 index 00000000..e0b78c1f --- /dev/null +++ b/tests/imports/test_module_imports.py @@ -0,0 +1,69 @@ +from importlib import import_module + +import pytest + + +def test_new_template_imports() -> None: + template = import_module("pptx_generator.template") + + assert hasattr(template, "load_jobspec_from_path") + assert hasattr(template, "extract_branding_config") + assert hasattr(template, "template_style_from_branding") + assert set(template.__all__) == { + "BrandingExtractionError", + "BrandingExtractionResult", + "SCHEME_COLOR_TAG", + "convert_scaffold_to_jobspec", + "extract_branding_config", + "extract_template_style", + "load_jobspec_from_path", + "template_style_from_branding", + } + + # 直接モジュールからも import できることを確認 + branding = import_module("pptx_generator.template.branding_extractor") + assert hasattr(branding, "BrandingExtractionError") + + spec_loader = import_module("pptx_generator.template.spec_loader") + assert hasattr(spec_loader, "convert_scaffold_to_jobspec") + + +def test_new_draft_imports() -> None: + draft = import_module("pptx_generator.draft") + + assert hasattr(draft, "CardLayoutRecommender") + assert hasattr(draft, "LayoutProfile") + assert hasattr(draft, "load_return_reasons") + assert set(draft.__all__) == { + "CardLayoutRecommender", + "CardLayoutRecommenderConfig", + "ChapterTemplate", + "ChapterTemplateEvaluation", + "ChapterTemplateSection", + "LayoutProfile", + "RecommendationResult", + "ReturnReasonTemplate", + "clamp_score_detail", + "compute_analyzer_support", + "evaluate_chapter_template", + "find_chapter_template_path", + "find_template_by_structure", + "load_analysis_summary", + "load_chapter_template", + "load_return_reasons", + "summarize_analyzer_counts", + } + + +@pytest.mark.parametrize( + "module_name", + [ + "pptx_generator.spec_loader", + "pptx_generator.branding_extractor", + "pptx_generator.draft_intel", + "pptx_generator.draft_recommender", + ], +) +def test_legacy_modules_removed(module_name: str) -> None: + with pytest.raises(ModuleNotFoundError): + import_module(module_name) diff --git a/tests/imports/test_no_legacy_references.py b/tests/imports/test_no_legacy_references.py new file mode 100644 index 00000000..021fae97 --- /dev/null +++ b/tests/imports/test_no_legacy_references.py @@ -0,0 +1,46 @@ +from pathlib import Path + +import pytest + +PROJECT_ROOT = Path(__file__).resolve().parents[2] +TARGET_DIRS = [ + PROJECT_ROOT / "docs", + PROJECT_ROOT / "samples", + PROJECT_ROOT / "scripts", +] +DEPRECATED_TOKENS = [ + "pptx_generator.spec_loader", + "pptx_generator.branding_extractor", + "pptx_generator.draft_intel", + "pptx_generator.draft_recommender", +] +TEXT_SUFFIXES = { + ".md", + ".py", + ".txt", + ".json", + ".toml", + ".yaml", + ".yml", + ".rst", + ".sh", +} + + +def _iter_text_files(base: Path) -> list[Path]: + files: list[Path] = [] + for path in base.rglob("*"): + if path.is_file() and path.suffix in TEXT_SUFFIXES: + files.append(path) + return files + + +@pytest.mark.parametrize("token", DEPRECATED_TOKENS) +def test_no_deprecated_references(token: str) -> None: + offenders: list[Path] = [] + for target in TARGET_DIRS: + for path in _iter_text_files(target): + text = path.read_text(encoding="utf-8") + if token in text: + offenders.append(path.relative_to(PROJECT_ROOT)) + assert not offenders, f"Deprecated token '{token}' found in: {offenders}" diff --git a/tests/integration/test_cli_generate_pipeline_flow.py b/tests/integration/test_cli_generate_pipeline_flow.py index d65c832e..d20907f7 100644 --- a/tests/integration/test_cli_generate_pipeline_flow.py +++ b/tests/integration/test_cli_generate_pipeline_flow.py @@ -16,7 +16,7 @@ from pptx import Presentation from pptx_generator import cli -from pptx_generator.branding_extractor import BrandingExtractionError +from pptx_generator.template import BrandingExtractionError from pptx_generator.cli import DEFAULT_GENERATE_READY_META_FILENAME, app from pptx_generator.layout_validation import LayoutValidationSuite from pptx_generator.models import (JobAuth, JobMeta, JobSpec, Slide, TemplateStyle, @@ -1220,7 +1220,7 @@ def test_cli_gen_template_branding_fallback(tmp_path, monkeypatch) -> None: prepare_paths=prepare_paths, ) - monkeypatch.setattr("pptx_generator.template_style.extract_branding_config", lambda _: ( + monkeypatch.setattr("pptx_generator.template.template_style.extract_branding_config", lambda _: ( _ for _ in ()).throw(BrandingExtractionError("boom"))) result = runner.invoke( diff --git a/tests/layout_ai/test_layout_recommender_scoring.py b/tests/layout_ai/test_layout_recommender_scoring.py index 85e2a691..cc4bb609 100644 --- a/tests/layout_ai/test_layout_recommender_scoring.py +++ b/tests/layout_ai/test_layout_recommender_scoring.py @@ -6,7 +6,7 @@ import pytest -from pptx_generator.draft_recommender import ( +from pptx_generator.draft import ( CardLayoutRecommender, CardLayoutRecommenderConfig, LayoutProfile, diff --git a/tests/pipeline/analyzer/test_analyzer_diagnostics.py b/tests/pipeline/analyzer/test_analyzer_diagnostics.py index 974ef238..4683cccf 100644 --- a/tests/pipeline/analyzer/test_analyzer_diagnostics.py +++ b/tests/pipeline/analyzer/test_analyzer_diagnostics.py @@ -44,7 +44,7 @@ SimpleAnalyzerStep, SimpleRendererStep, ) -from pptx_generator.generate_ready import generate_ready_to_jobspec +from pptx_generator.pipeline.generate_ready import generate_ready_to_jobspec from pptx_generator.pipeline.analyzer import ( BulletParagraphResolver, ShapeSnapshot, diff --git a/tests/pipeline/compose/test_draft_structuring_step.py b/tests/pipeline/compose/test_draft_structuring_step.py index f4ab71f1..3e859081 100644 --- a/tests/pipeline/compose/test_draft_structuring_step.py +++ b/tests/pipeline/compose/test_draft_structuring_step.py @@ -26,7 +26,7 @@ SlideTable, TemplateBlueprintSlot, ) -from pptx_generator.draft_recommender import LayoutProfile +from pptx_generator.draft import LayoutProfile from pptx_generator.prepare import ( PrepareBodyBlock, PrepareCard, diff --git a/tests/pipeline/compose/test_dynamic_flow.py b/tests/pipeline/compose/test_dynamic_flow.py index c1e6b1ac..f64d7944 100644 --- a/tests/pipeline/compose/test_dynamic_flow.py +++ b/tests/pipeline/compose/test_dynamic_flow.py @@ -3,7 +3,7 @@ from types import SimpleNamespace from typing import Any -from pptx_generator.draft_recommender import LayoutProfile, RecommendationResult +from pptx_generator.draft import LayoutProfile, RecommendationResult from pptx_generator.layout_ai.client import LayoutAIResponse from pptx_generator.models import ( ContentElements, diff --git a/tests/pipeline/draft_structuring/test_generate_ready_runtime.py b/tests/pipeline/draft_structuring/test_generate_ready_runtime.py index 84d092f0..7e757db2 100644 --- a/tests/pipeline/draft_structuring/test_generate_ready_runtime.py +++ b/tests/pipeline/draft_structuring/test_generate_ready_runtime.py @@ -6,7 +6,7 @@ import pytest -from pptx_generator.draft_recommender import LayoutProfile +from pptx_generator.draft import LayoutProfile from pptx_generator.models import ( ContentApprovalDocument, ContentElements, diff --git a/tests/pipeline/test_pipeline_trace.py b/tests/pipeline/test_pipeline_trace.py index f28b25a9..62243b3c 100644 --- a/tests/pipeline/test_pipeline_trace.py +++ b/tests/pipeline/test_pipeline_trace.py @@ -1,7 +1,7 @@ import json from pathlib import Path -from pptx_generator.config_manager import ResolvedConfig +from pptx_generator.config import ResolvedConfig from pptx_generator.models import JobAuth, JobMeta, JobSpec, Slide from pptx_generator.pipeline import PipelineContext, PipelineStage, StageResult from pptx_generator.pipeline.trace import write_pipeline_trace diff --git a/tests/spec_loader/test_spec_loader_conversion.py b/tests/spec_loader/test_spec_loader_conversion.py index 1ee484fb..218e7b19 100644 --- a/tests/spec_loader/test_spec_loader_conversion.py +++ b/tests/spec_loader/test_spec_loader_conversion.py @@ -7,7 +7,7 @@ import json from pptx_generator.models import JobSpec -from pptx_generator.spec_loader import load_jobspec_from_path +from pptx_generator.template import load_jobspec_from_path def test_load_jobspec_from_scaffold() -> None: diff --git a/tests/template_audit/test_template_extractor_jobspec_output.py b/tests/template_audit/test_template_extractor_jobspec_output.py index 78922dee..ae0e3791 100644 --- a/tests/template_audit/test_template_extractor_jobspec_output.py +++ b/tests/template_audit/test_template_extractor_jobspec_output.py @@ -11,7 +11,7 @@ from pptx_generator.models import (JobSpecScaffold, LayoutInfo, ShapeInfo, TemplateSpec) -from pptx_generator.spec_loader import convert_scaffold_to_jobspec +from pptx_generator.template import convert_scaffold_to_jobspec from pptx_generator.pipeline.template_extractor import ( JOBSPEC_SCHEMA_VERSION, SLIDE_BULLET_ANCHORS, diff --git a/tests/utils/test_config_manager.py b/tests/utils/test_config_manager.py index aef7bbe1..372a7df4 100644 --- a/tests/utils/test_config_manager.py +++ b/tests/utils/test_config_manager.py @@ -1,4 +1,4 @@ -from pptx_generator.config_manager import ConfigManager +from pptx_generator.config import ConfigManager def test_config_manager_prefers_higher_priority() -> None: