kina006097 commited on
Commit
d270dd6
·
1 Parent(s): 5e60243

CICDのタスク追加

Browse files
Files changed (1) hide show
  1. docs/ai_api_development_guide.md +107 -62
docs/ai_api_development_guide.md CHANGED
@@ -9,7 +9,7 @@
9
  本プロジェクトの目的は、「親子で遊ぼうナビ」にAIを活用した**口コミの自動要約機能**を実装することです。
10
 
11
  - **目的:** ユーザーが多数の口コミを全て読んでも、施設の全体的な評判を素早く、かつ客観的に把握できるようにする。
12
- - **ユーザー体験:**
13
  1. ユーザーは施設の詳細ページで「口コミをAI要約」ボタンをクリックします。
14
  2. AIがその施設の全口コミを分析し、「ポジティブな点」と「注意が必要な点」などをまとめた中立的な要約文を生成します。
15
  3. 生成された要約がモーダルウィンドウ等で表示され、ユーザーは短時間で施設の長所と短所を理解できます。
@@ -159,7 +159,7 @@ AI新機能の開発においては、以下のコーディング規約と開発
159
  * **PEP 8準拠**: PythonコードはPEP 8スタイルガイドに厳密に準拠します。`flake8` および `black` による自動フォーマットとリントを徹底し、コードの一貫性を保ちます。
160
  * **型ヒントの活用**: `mypy` を用いた型チェックを徹底し、コードの堅牢性、可読性、およびIDEによる補完の恩恵を最大化します。
161
  * **Djangoとの連携**: AI機能がDjangoアプリケーションと連携する場合、Djangoのモデル、ビュー、フォーム、URLパターンなどの既存の命名規則と構造に準拠し、シームレスな統合を図ります。
162
- * **AI/MLコードの構造**:
163
  * データ処理(前処理、特徴量エンジニアリング)、モデル定義、学習ロジック、推論ロジックは明確に分離し、それぞれが単一の責務を持つモジュールとして設計します。
164
  * 設定値やハイパーパラメータはコードから分離し、Djangoの`settings.py`、または専用のYAML/JSONファイルなどで一元的に管理します。
165
  * **ドキュメンテーション**: 関数、クラス、複雑なアルゴリズム、およびAIモデルの設計意図には、適切なDocstringを記述し、コードの意図と振る舞いを明確にします。
@@ -189,12 +189,15 @@ AI新機能の開発においては、以下のコーディング規約と開発
189
  ## 6. CI/CDとデプロイ戦略
190
 
191
  ### 6.1. 推奨ワークフロー
192
- 1. **CI (GitHub Actions):** プルリクエスト作成時やmainブランチへのプッシュ時に、GitHub Actionsを起動し、`pytest`による自動テスト(ユニットテストとインテグレーションテスト)を実行します。
193
- 2. **CD (Hugging Face Hub連携):** テストが成功したコードがmainブランチにマージされたら、Hugging Face Hubの**GitHub連携機能**がそれを検知し、自動的にSpacesにデプロイします。この方法が、Actionsから手動で`git push`するよりシンプルで確実なため推奨されます。
194
 
195
  ### 6.2. 設定
196
- - **GitHub Actions:** `.github/workflows/ci.yml`にテストのワークフローを定義します。
197
- - **Hugging Face Hub:** Spacesの設定ページで、対象のGitHubリポジトリとブランチを指定して連携を有効化します。
 
 
 
198
 
199
  ---
200
 
@@ -209,7 +212,7 @@ AI新機能の開発においては、以下のコーディング規約と開発
209
  2. **Secretsへの登録:** 生成したキーを、DjangoとGradio APIの両方の環境変数(Hugging Face SpacesのSecrets)として登録します。
210
  - `AI_API_KEY`: Gradio側でリクエストを検証するためのキー
211
  - `DJANGO_AI_API_KEY`: Djangoがリクエスト時に送信するキー
212
- 3. **認証の実装:**
213
  - **Django側:** APIを呼び出す際、HTTPヘッダー(例: `Authorization: Bearer <APIキー>`)にAPIキーを含��て送信します。
214
  - **Gradio側:** FastAPIの依存性注入(`Depends`)などを利用して、リクエストヘッダーをチェックする認証関数を定義します。APIキーが一致しない場合は、HTTP 401または403エラーを返却します。
215
 
@@ -319,20 +322,20 @@ AIの性能を最大限に引き出し、安定した運用を行うための内
319
  #### 9.4.1. エラー発生源と対応方針
320
 
321
  | 発生場所 | エラー例 | 対応方針 | ユーザーへの通知例 |
322
- | :--- | : | : | : |
323
  | **Gradio API** | モデルのロード失敗、推論中のエラー | `try...except`で捕捉し、HTTP 500とエラー内容をJSONで返す。 | (Django経由で)「AIサーバーで問題が発生」 |
324
  | **Django ⇔ Gradio API間** | ネットワーク障害、タイムアウト | Djangoの`requests`部分で`try...except`で捕捉し、エラーをログ記録。 | 「AIサーバーに応答がありません」 |
325
  | **Django** | DB接続エラー、口コミ件数不足 | `try...except`や条件分岐で対応。口コミ不足はHTTP 400を返す。 | 「サーバーでエラーが発生」、または「口コミが不足」 |
326
  | **ブラウザ ⇔ Django間** | ユーザーのオフライン | jQuery Ajaxの`.fail()`コールバックで捕捉。 | 「通信に失敗しました」 |
327
 
328
  #### 9.4.2. 実装のポイント
329
- - **Django (司令塔) の役割:**
330
  - Djangoのビューは、Gradio APIとの通信部分を必ず`try...except`ブロックで囲み、タイムアウト(例: 30秒)を設定します。
331
  - APIから返されたHTTPステータスコードを常にチェックし、200番台以外はエラーとして処理します。
332
  - 発生したエラーは、**必ずサーバーログに記録**し、原因調査に役立てます。
333
  - ユーザーには、技術的なエラー詳細(スタックトレース等)を直接見せず、「AIサーバーで問題が発生しました」のような抽象的で分かりやすいメッセージを返します。
334
 
335
- - **Gradio API (専門家) の役割:**
336
  - AIの推論処理など、失敗する可能性のあるコードは`try...except`ブロックで囲みます。
337
  - エラー発生時は、`raise gr.Error("具体的なエラー原因")`を呼び出し、APIの契約通りにエラー情報を返却します。
338
 
@@ -423,18 +426,18 @@ Django側でAI APIを呼び出すビューは、責務を明確に分離し、
423
  アプリケーションの品質と信頼性を保証するため、以下の通り多層的なテスト戦略を設計します。
424
 
425
  #### 9.8.1. テストの種類と目的
426
- - **ユニットテスト (Unit Tests):**
427
  - **目的:** 個々の部品(クラス、メソッド)が単体で正しく動作することを検証します。高速に実行できるため、開発中の頻繁な確認に適しています。
428
  - **対象:** `core/inference.py` の `Summarizer` クラスなど、ビジネスロジックの中核を担う部分。
429
- - **インテグレーションテスト (Integration Tests):**
430
  - **目的:** Gradio APIのエンドポイントが、APIの契約通りに正しくリクエストを処理し、レスポンスを返すことを検証します。コンポーネント間の連携を確認します。
431
  - **対象:** ローカルで起動したGradioアプリケーションの `/api/predict/` エンドポイント。
432
 
433
  #### 9.8.2. テストケースの計画
434
- - **ユニットテスト (`tests/core/test_inference.py`):**
435
  - **正常系:** 通常のテキストが入力された場合に、期待される形式(文字列)の要約が返ることを確認する。
436
  - **異常系:** 空文字列や不正なデータ型が入力された場合に、設計通り`ValueError`等の例外が発生することを確認する。
437
- - **インテグレーションテスト (`tests/test_api.py`):**
438
  - **正常系:** APIに有効なリクエストを送信し、HTTPステータスコード`200`と、設計通りのJSONレスポンスが返ることを確認する。
439
  - **異常系:** 不正なリクエストを送信した場合に、適切なHTTPエラーステータスコード(例: `4xx`)が返ることを確認する。
440
 
@@ -494,13 +497,13 @@ sequenceDiagram
494
  - **クラス:** `SummarizeReviewsView(View)`
495
  - **メソッド:** `get(self, request, playground_id)`
496
  - **責務:** リクエストを受け付け、AI APIとの通信を制御する司令塔。
497
- - **処理フロー:**
498
  1. DBから口コミを取得し、件数や文字数を検証する。
499
  2. `_call_summary_api` メソッドを呼び出し、AI APIにリクエストを送信する。
500
  3. 返ってきた結果(成功またはエラー)を整形し、`JsonResponse`としてフロントエンドに返す。
501
  - **メソッド:** `_call_summary_api(self, text)`
502
  - **責務:** `requests`ライブラリを用いて、AI APIとのHTTP通信を実際に担当する。
503
- - **実装詳細:**
504
  - `settings.AI_SUMMARY_API_URL` からAPIのエンドポイントURLを取得する。
505
  - `requests.post()` を使い、タイムアウトを設定してPOSTリクエストを送信する。
506
  - 通信エラーや、APIが返すエラーステータスコードを`try...except`で捕捉し、適切に処理する。
@@ -510,7 +513,7 @@ sequenceDiagram
510
 
511
  - **ファイル:** `main.py` (エントリーポイント)
512
  - **責務:** Gradioアプリケーションを起動し、HTTPリクエストを受け付ける窓口。
513
- - **実装詳細:**
514
  1. 起動時に一度だけ、`core.inference.Summarizer` クラスのインスタンスを生成する。
515
  2. `functools.partial` を使い、API処理関数に `Summarizer` のインスタンスを注入(バインド)する。
516
  3. `gradio.Interface` を定義し、リクエストを処理する関数として上記でバインドした関数を渡す。これにより、Gradioは `/api/predict/` というエンドポイントを自動的に作成する。
@@ -524,16 +527,16 @@ sequenceDiagram
524
 
525
  この設計が、いかにして疎結合(Loose Coupling)を担保しているかを以下に示します。
526
 
527
- - **通信の抽象化:**
528
  - DjangoとAIアプリは、**HTTPとJSON**という標準化された技術でのみ通信します。
529
  - DjangoはAIアプリがGradioで実装されていることを知る必要はなく、逆もまた然りです。知っているのは「どのURLに、どんなJSONを送れば、どんなJSONが返ってくるか」というAPI契約だけです。
530
 
531
- - **独立した実行とテスト:**
532
- - **AIアプリケーション:**
533
  - `src/ai_api/` ディレクトリは、それ自体が完結したPythonプロジェクトです。
534
  - `python src/ai_api/main.py` を実行すれば、Djangoとは無関係に単体で起動できます。
535
  - 起動したAIアプリに対し、ブラウザでUIを操作したり、`curl`コマンドでAPIを直接叩いたりすることで、単体での動作テストが可能です。
536
- - **Djangoアプリケーション:**
537
  - `SummarizeReviewsView` のテストを書く際、`unittest.mock.patch` を使って `_call_summary_api` メソッドをモック(偽のオブジェクトに差し替え)します。
538
  - これにより、AI APIへ実際にネットワーク通信を発生させることなく、「APIが成功を返した場合」「タイムアウトした場合」「エラーを返した場合」など、あらゆる状況を想定したビューのロジックを高速にテストできます。
539
 
@@ -662,7 +665,7 @@ cd kids-playground-ai-api
662
  git init
663
  # .gitignore ファイルを作成または編集し、適切な内容を記述
664
  # 例:
665
- # echo "__pycache__\nvenv/\.env" > .gitignore
666
  git add .
667
  git commit -m "Initial commit"
668
  ```
@@ -670,7 +673,7 @@ git commit -m "Initial commit"
670
  - [x] **中タスク0.3: GitHubリポジトリの作成と連携**
671
  - **担当:** 人間
672
  - **内容:** GitHub上に新しいリポジトリを作成し、ローカルリポジトリと連携させます。
673
- - **指示:**
674
  1. GitHubにログインし、新しいリポジトリを作成します(リポジトリ名は `kids-playground-ai-api` など)。READMEや.gitignore、ライセンスの追加はスキップしてください。
675
  2. 作成されたリポジトリページに表示される指示に従い、ローカルリポジトリをリモートにプッシュします。
676
  ```bash
@@ -682,11 +685,10 @@ git push -u origin main
682
  - [x] **中タスク0.4: Hugging Faceアカウントの登録とSpacesの準備**
683
  - [x] **担当:** 人間
684
  - [x] **内容:** Hugging Faceアカウントを登録し、AIモデルをデプロイするためのHugging Face Spaceを準備します。
685
- - [x] **指示:**
686
  1. Hugging Faceのウェブサイト (huggingface.co) にアクセスし、アカウントを登録します。
687
  2. ログイン後、「Spaces」セクションに移動し、「Create new Space」をクリックします。
688
  3. Space名、ライセンス、SDK(Gradioを選択)、公開/非公開設定などを適切に設定し、Spaceを作成します。
689
- 4. 作成後、Spaceの設定ページで「Link to a Git repository」オプションを探し、先ほど作成したGitHubリポジトリと連携させます。これにより、GitHubへのプッシュで自動デプロイが可能になります。
690
 
691
  - [x] **中タスク0.5: ライセンスファイルの作成**
692
  - **担当:** AI
@@ -750,7 +752,7 @@ mypy
750
  - [x] **小タスク1.3.2: Docker開発環境の構築と起動**
751
  - **担当:** 人間
752
  - **内容:** Docker Desktopを利用して、プロジェクトのDocker開発環境を構築し、起動します。これにより、必要な依存関係がコンテナ内に自動的にインストールされます。
753
- - **指示:**
754
  1. Docker Desktopがインストールされ、起動していることを確認してください。
755
  2. プロジェクトのルートディレクトリで、以下のコマンドを実行してDockerコンテナをビルドし、バックグラウンドで起動します。
756
  ```bash
@@ -763,98 +765,141 @@ docker-compose up --build -d
763
  - **内容:** 環境変数設定ファイル(`.env`)とそのテンプレート(`.env.example`)を作成します。
764
  - **指示:** プロジェクトのルートディレクトリに`.env`ファイルと`.env.example`ファイルを作成してください。
765
 
766
- - [x] **中タスク1.4: 環境変数設定ファイルの準備 (`.env`, `.env.example`)**
767
- - **担当:** AI
768
- - **内容:** 環境変数設定ファイル(`.env`)とそのテンプレート(`.env.example`)を作成します。
769
- - **指示:** プロジェクトのルートディレクトリに`.env`ファイルと`.env.example`ファイルを作成してください。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
770
 
771
- ### フェーズ2: AIアプリケーションのTDD (コアロジック → API)
772
 
773
  **目的:** クリーンアーキテクチャの原則に従い、内側のビジネスロジックから外側のAPIへと実装を進める。
774
 
775
- - [ ] **中タスク2.1: AIコアロジック `Summarizer` の実装**
776
- - [ ] **小タスク2.1.1 (RED):** `Summarizer`クラスのテスト作成
777
  - **担当:** AI
778
  - **内容:** `tests/core/test_inference.py` を作成し、「`from src.ai_api.core.inference import Summarizer` が成功すること」をテストします。このテストは、ファイルやクラスが存在しないため失敗します。
779
- - [ ] **小タスク2.1.2 (GREEN):** `Summarizer`クラスの骨格作成
780
  - **担当:** AI
781
  - **内容:** `src/ai_api/core/inference.py` と、空の`Summarizer`クラスを作成し、テストをパスさせます。
782
- - [ ] **小タスク2.1.3 (REFACTOR):** リファクタリング
783
  - **担当:** AI
784
  - **内容:** この時点では特になし。コミットの区切りとします。
785
 
786
- - [ ] **中タスク2.2: AI設定クラス `Config` の実装と注入**
787
- - [ ] **小タスク2.2.1 (RED):** `Summarizer`が設定オブジェクトを受け取るテスト作成
788
  - **担当:** AI
789
  - **内容:** `tests/core/test_inference.py`に追記します。
790
  - **内容:** `Summarizer`がコンストラクタで設定オブジェクト(モデル名など)を受け取ることを期待するテストを`tests/core/test_inference.py`に追記します。
791
- - [ ] **小タスク2.2.2 (GREEN):** 設定クラスの作成とコンストラクタ修正
792
  - **担当:** AI
793
  - **内容:** `src/ai_api/config.py`に設計通りの設定クラス(`ModelConfig`など)を作成します。`Summarizer`の`__init__`を修正し、設定オブジェクトを受け取るようにします。
794
- - [ ] **小タスク2.2.3 (REFACTOR):** リファクタリング
795
  - **担当:** AI
796
  - **内容:** コードの可読性を向上させます。 **この時点で、AIモデルを切り替えるための基本的な仕組み(設定値を外部から与える)が完成します。**
797
 
798
- - [ ] **中タスク2.3: 要約機能 `summarize` メソッドの実装**
799
- - [ ] **小タスク2.3.1 (RED):** `summarize`メソッドのユニットテスト作成
800
  - **担当:** AI
801
  - **内容:** `unittest.mock.patch`を使い、`transformers.pipeline`をモック(偽物に差し替え)します。「`summarize`メソッドを呼ぶと、内部で`pipeline`が特定の引数で呼ばれ、モックの返り値がそのまま返されること」をテストします。これにより、重いモデルをロードせずにロジックだけを高速にテストできます。
802
- - [ ] **小タスク2.3.2 (GREEN):** `summarize`メソッドの実装
803
  - **担当:** AI
804
  - **内容:** `Summarizer`クラスに`summarize`メソッドを実装し、内部で`transformers.pipeline`を呼び出して要約を実行するようにします。
805
- - [ ] **小タスク2.3.3 (REFACTOR):** リファクタリング
806
  - **担当:** AI
807
  - **内容:** エラーハンドリングなどを追加し、コードを整理します。
808
 
809
- - [ ] **中タスク2.4: APIエントリーポイント `main.py` の実装**
810
- - [ ] **小タスク2.4.1 (RED):** APIのインテグレーションテスト作成
811
  - **担当:** AI
812
  - **内容:** `tests/test_api.py`を作成します。テスト内でGradioアプリを別スレッドで起動し、`requests.post`で`/api/predict/`にリクエストを送信して、期待した応答が得られない(サーバーがないため)ことを確認します。
813
- - [ ] **小タスク2.4.2 (GREEN):** `main.py`の実装
814
  - **担当:** AI
815
  - **内容:** `src/ai_api/main.py`を作成します。`Summarizer`と設定クラスをインスタンス化し、DI(依存性の注入)してGradioの`Interface`を定義・起動します。
816
- - [ ] **小タスク2.4.3 (REFACTOR):** リファクタリング
817
  - **担当:** AI
818
  - **内容:** コードを整理します。
819
- - [ ] **小タスク2.4.4: 手動での動作確認**
820
  - **担当:** 人間
821
  - **内容:** `python src/ai_api/main.py` を実行し、ブラウザで表示されるGradioのUIにテキストを入力して、要約機能が単体で正しく動作することを確認します。
822
 
823
- ### フェーズ3: Djangoへの組み込み
824
 
825
  **目的:** 独立して動作するAIアプリケーションを、DjangoからAPI経由で安全に呼び出す。
826
 
827
- - [ ] **中タスク3.1: Django側のAPIクライアント実装**
828
- - [ ] **小タスク3.1.1 (RED):** APIクライアントのテスト作成
829
  - **担当:** AI
830
  - **内容:** `myapp/tests/test_clients.py`を作成します。`requests.post`がモック化されている状態でAPIクライアント関数を呼び出し、成功時・タイムアウト時・サーバーエラー時の挙動をテストします。
831
- - [ ] **小タスク3.1.2 (GREEN):** APIクライアントの実装
832
  - **担当:** AI
833
  - **内容:** `myapp/clients/ai_summary_client.py`を作成し、`requests`を使って外部APIを呼び出す関数を実装します。
834
- - [ ] **小タスク3.1.3 (REFACTOR):** リファクタリング
835
  - **担当:** AI
836
  - **内容:** 設定を`settings.py`から読み込むようにするなど、コードを整理します。
837
 
838
- - [ ] **中タスク3.2: Django Viewの実装**
839
- - [ ] **小タスク3.2.1 (RED):** ViewのURLテスト作成
840
  - **担当:** AI
841
  - **内容:** `myapp/tests/test_views.py`に、`/summarize/playground/{id}/`へのGETリクエストが404を返すテストを書きます。
842
- - [ ] **小タスク3.2.2 (GREEN):** URLとViewの骨格作成
843
  - **担当:** AI
844
  - **内容:** `myapp/urls.py`と`myapp/views/summary_views.py`を作成・編集し、テストをパスさせます。
845
- - [ ] **小タスク3.2.3 (RED):** Viewとクライアントの連携テスト作成
846
  - **担当:** AI
847
  - **内容:** `unittest.mock.patch`でAPIクライアントをモック化し、「Viewを呼び出すと、内部でAPIクライアントが特定の引数で呼ばれること」をテストします。
848
- - [ ] **小タスク3.2.4 (GREEN):** Viewロジックの実装
849
  - **担当:** AI
850
  - **内容:** View内で口コミの取得・検証ロジック、およびAPIクライアントの呼び出しを実装します。
851
- - [ ] **小タスク3.2.5 (REFACTOR):** リファクタリング
852
  - **担当:** AI
853
  - **内容:** コードを整理します。
854
 
855
- - [ ] **中タスク3.3: 統合テスト**
856
- - [ ] **小タスク3.3.1: 手動での最終確認**
857
  - **担当:** 人間
858
  - **内容:** DjangoサーバーとAIアプリ(Gradio)を両方ローカルで起動し、ブラウザから最初の要約ボタンをクリックして、全体の流れが正しく動作するかを確認します。
859
 
860
- ```
 
9
  本プロジェクトの目的は、「親子で遊ぼうナビ」にAIを活用した**口コミの自動要約機能**を実装することです。
10
 
11
  - **目的:** ユーザーが多数の口コミを全て読んでも、施設の全体的な評判を素早く、かつ客観的に把握できるようにする。
12
+ - **ユーザー体験:**
13
  1. ユーザーは施設の詳細ページで「口コミをAI要約」ボタンをクリックします。
14
  2. AIがその施設の全口コミを分析し、「ポジティブな点」と「注意が必要な点」などをまとめた中立的な要約文を生成します。
15
  3. 生成された要約がモーダルウィンドウ等で表示され、ユーザーは短時間で施設の長所と短所を理解できます。
 
159
  * **PEP 8準拠**: PythonコードはPEP 8スタイルガイドに厳密に準拠します。`flake8` および `black` による自動フォーマットとリントを徹底し、コードの一貫性を保ちます。
160
  * **型ヒントの活用**: `mypy` を用いた型チェックを徹底し、コードの堅牢性、可読性、およびIDEによる補完の恩恵を最大化します。
161
  * **Djangoとの連携**: AI機能がDjangoアプリケーションと連携する場合、Djangoのモデル、ビュー、フォーム、URLパターンなどの既存の命名規則と構造に準拠し、シームレスな統合を図ります。
162
+ * **AI/MLコードの構造**:
163
  * データ処理(前処理、特徴量エンジニアリング)、モデル定義、学習ロジック、推論ロジックは明確に分離し、それぞれが単一の責務を持つモジュールとして設計します。
164
  * 設定値やハイパーパラメータはコードから分離し、Djangoの`settings.py`、または専用のYAML/JSONファイルなどで一元的に管理します。
165
  * **ドキュメンテーション**: 関数、クラス、複雑なアルゴリズム、およびAIモデルの設計意図には、適切なDocstringを記述し、コードの意図と振る舞いを明確にします。
 
189
  ## 6. CI/CDとデプロイ戦略
190
 
191
  ### 6.1. 推奨ワークフロー
192
+ 1. **CI (GitHub Actions):** プルリクエスト作成時や`main`ブランチへのプッシュ時に、GitHub Actionsを起動し、`pytest`による自動テスト(ユニットテストとインテグレーションテスト)を実行します。
193
+ 2. **CD (GitHub Actionsによるデプロイ):** テストが成功したコードが`main`ブランチにマージされたら、GitHub ActionsのワークフローがHugging Faceのアクセストークンを使って、Hugging Face Spacesのリポジトリに直接`git push`します。これにより、デプロイが自動的に実行されます。
194
 
195
  ### 6.2. 設定
196
+ - **GitHub Actions:** `.github/workflows/ci.yml`にテストとデプロイのワークフローを定義します。
197
+ - **Hugging Face Hub & GitHub Secrets:**
198
+ 1. Hugging Faceの個人設定で、`write`権限を持つアクセストークンを発行します。
199
+ 2. 発行したトークンを、GitHubリポジトリの`Settings > Secrets and variables > Actions`に`HF_TOKEN`として登録します。
200
+ 3. `ci.yml`内のデプロイジョブは、この`HF_TOKEN`を安全に利用してHugging Faceへの認証を行います。
201
 
202
  ---
203
 
 
212
  2. **Secretsへの登録:** 生成したキーを、DjangoとGradio APIの両方の環境変数(Hugging Face SpacesのSecrets)として登録します。
213
  - `AI_API_KEY`: Gradio側でリクエストを検証するためのキー
214
  - `DJANGO_AI_API_KEY`: Djangoがリクエスト時に送信するキー
215
+ 3. **認証の実装:**
216
  - **Django側:** APIを呼び出す際、HTTPヘッダー(例: `Authorization: Bearer <APIキー>`)にAPIキーを含��て送信します。
217
  - **Gradio側:** FastAPIの依存性注入(`Depends`)などを利用して、リクエストヘッダーをチェックする認証関数を定義します。APIキーが一致しない場合は、HTTP 401または403エラーを返却します。
218
 
 
322
  #### 9.4.1. エラー発生源と対応方針
323
 
324
  | 発生場所 | エラー例 | 対応方針 | ユーザーへの通知例 |
325
+ | :--- | :--- | :--- | :--- |
326
  | **Gradio API** | モデルのロード失敗、推論中のエラー | `try...except`で捕捉し、HTTP 500とエラー内容をJSONで返す。 | (Django経由で)「AIサーバーで問題が発生」 |
327
  | **Django ⇔ Gradio API間** | ネットワーク障害、タイムアウト | Djangoの`requests`部分で`try...except`で捕捉し、エラーをログ記録。 | 「AIサーバーに応答がありません」 |
328
  | **Django** | DB接続エラー、口コミ件数不足 | `try...except`や条件分岐で対応。口コミ不足はHTTP 400を返す。 | 「サーバーでエラーが発生」、または「口コミが不足」 |
329
  | **ブラウザ ⇔ Django間** | ユーザーのオフライン | jQuery Ajaxの`.fail()`コールバックで捕捉。 | 「通信に失敗しました」 |
330
 
331
  #### 9.4.2. 実装のポイント
332
+ - **Django (司令塔) の役割:**
333
  - Djangoのビューは、Gradio APIとの通信部分を必ず`try...except`ブロックで囲み、タイムアウト(例: 30秒)を設定します。
334
  - APIから返されたHTTPステータスコードを常にチェックし、200番台以外はエラーとして処理します。
335
  - 発生したエラーは、**必ずサーバーログに記録**し、原因調査に役立てます。
336
  - ユーザーには、技術的なエラー詳細(スタックトレース等)を直接見せず、「AIサーバーで問題が発生しました」のような抽象的で分かりやすいメッセージを返します。
337
 
338
+ - **Gradio API (専門家) の役割:**
339
  - AIの推論処理など、失敗する可能性のあるコードは`try...except`ブロックで囲みます。
340
  - エラー発生時は、`raise gr.Error("具体的なエラー原因")`を呼び出し、APIの契約通りにエラー情報を返却します。
341
 
 
426
  アプリケーションの品質と信頼性を保証するため、以下の通り多層的なテスト戦略を設計します。
427
 
428
  #### 9.8.1. テストの種類と目的
429
+ - **ユニットテスト (Unit Tests):**
430
  - **目的:** 個々の部品(クラス、メソッド)が単体で正しく動作することを検証します。高速に実行できるため、開発中の頻繁な確認に適しています。
431
  - **対象:** `core/inference.py` の `Summarizer` クラスなど、ビジネスロジックの中核を担う部分。
432
+ - **インテグレーションテスト (Integration Tests):**
433
  - **目的:** Gradio APIのエンドポイントが、APIの契約通りに正しくリクエストを処理し、レスポンスを返すことを検証します。コンポーネント間の連携を確認します。
434
  - **対象:** ローカルで起動したGradioアプリケーションの `/api/predict/` エンドポイント。
435
 
436
  #### 9.8.2. テストケースの計画
437
+ - **ユニットテスト (`tests/core/test_inference.py`):**
438
  - **正常系:** 通常のテキストが入力された場合に、期待される形式(文字列)の要約が返ることを確認する。
439
  - **異常系:** 空文字列や不正なデータ型が入力された場合に、設計通り`ValueError`等の例外が発生することを確認する。
440
+ - **インテグレーションテスト (`tests/test_api.py`):**
441
  - **正常系:** APIに有効なリクエストを送信し、HTTPステータスコード`200`と、設計通りのJSONレスポンスが返ることを確認する。
442
  - **異常系:** 不正なリクエストを送信した場合に、適切なHTTPエラーステータスコード(例: `4xx`)が返ることを確認する。
443
 
 
497
  - **クラス:** `SummarizeReviewsView(View)`
498
  - **メソッド:** `get(self, request, playground_id)`
499
  - **責務:** リクエストを受け付け、AI APIとの通信を制御する司令塔。
500
+ - **処理フロー:**
501
  1. DBから口コミを取得し、件数や文字数を検証する。
502
  2. `_call_summary_api` メソッドを呼び出し、AI APIにリクエストを送信する。
503
  3. 返ってきた結果(成功またはエラー)を整形し、`JsonResponse`としてフロントエンドに返す。
504
  - **メソッド:** `_call_summary_api(self, text)`
505
  - **責務:** `requests`ライブラリを用いて、AI APIとのHTTP通信を実際に担当する。
506
+ - **実装詳細:**
507
  - `settings.AI_SUMMARY_API_URL` からAPIのエンドポイントURLを取得する。
508
  - `requests.post()` を使い、タイムアウトを設定してPOSTリクエストを送信する。
509
  - 通信エラーや、APIが返すエラーステータスコードを`try...except`で捕捉し、適切に処理する。
 
513
 
514
  - **ファイル:** `main.py` (エントリーポイント)
515
  - **責務:** Gradioアプリケーションを起動し、HTTPリクエストを受け付ける窓口。
516
+ - **実装詳細:**
517
  1. 起動時に一度だけ、`core.inference.Summarizer` クラスのインスタンスを生成する。
518
  2. `functools.partial` を使い、API処理関数に `Summarizer` のインスタンスを注入(バインド)する。
519
  3. `gradio.Interface` を定義し、リクエストを処理する関数として上記でバインドした関数を渡す。これにより、Gradioは `/api/predict/` というエンドポイントを自動的に作成する。
 
527
 
528
  この設計が、いかにして疎結合(Loose Coupling)を担保しているかを以下に示します。
529
 
530
+ - **通信の抽象化:**
531
  - DjangoとAIアプリは、**HTTPとJSON**という標準化された技術でのみ通信します。
532
  - DjangoはAIアプリがGradioで実装されていることを知る必要はなく、逆もまた然りです。知っているのは「どのURLに、どんなJSONを送れば、どんなJSONが返ってくるか」というAPI契約だけです。
533
 
534
+ - **独立した実行とテスト:**
535
+ - **AIアプリケーション:**
536
  - `src/ai_api/` ディレクトリは、それ自体が完結したPythonプロジェクトです。
537
  - `python src/ai_api/main.py` を実行すれば、Djangoとは無関係に単体で起動できます。
538
  - 起動したAIアプリに対し、ブラウザでUIを操作したり、`curl`コマンドでAPIを直接叩いたりすることで、単体での動作テストが可能です。
539
+ - **Djangoアプリケーション:**
540
  - `SummarizeReviewsView` のテストを書く際、`unittest.mock.patch` を使って `_call_summary_api` メソッドをモック(偽のオブジェクトに差し替え)します。
541
  - これにより、AI APIへ実際にネットワーク通信を発生させることなく、「APIが成功を返した場合」「タイムアウトした場合」「エラーを返した場合」など、あらゆる状況を想定したビューのロジックを高速にテストできます。
542
 
 
665
  git init
666
  # .gitignore ファイルを作成または編集し、適切な内容を記述
667
  # 例:
668
+ # echo "__pycache__\nvirtualenv/\.env" > .gitignore
669
  git add .
670
  git commit -m "Initial commit"
671
  ```
 
673
  - [x] **中タスク0.3: GitHubリポジトリの作成と連携**
674
  - **担当:** 人間
675
  - **内容:** GitHub上に新しいリポジトリを作成し、ローカルリポジトリと連携させます。
676
+ - **指示:**
677
  1. GitHubにログインし、新しいリポジトリを作成します(リポジトリ名は `kids-playground-ai-api` など)。READMEや.gitignore、ライセンスの追加はスキップしてください。
678
  2. 作成されたリポジトリページに表示される指示に従い、ローカルリポジトリをリモートにプッシュします。
679
  ```bash
 
685
  - [x] **中タスク0.4: Hugging Faceアカウントの登録とSpacesの準備**
686
  - [x] **担当:** 人間
687
  - [x] **内容:** Hugging Faceアカウントを登録し、AIモデルをデプロイするためのHugging Face Spaceを準備します。
688
+ - [x] **指示:**
689
  1. Hugging Faceのウェブサイト (huggingface.co) にアクセスし、アカウントを登録します。
690
  2. ログイン後、「Spaces」セクションに移動し、「Create new Space」をクリックします。
691
  3. Space名、ライセンス、SDK(Gradioを選択)、公開/非公開設定などを適切に設定し、Spaceを作成します。
 
692
 
693
  - [x] **中タスク0.5: ライセンスファイルの作成**
694
  - **担当:** AI
 
752
  - [x] **小タスク1.3.2: Docker開発環境の構築と起動**
753
  - **担当:** 人間
754
  - **内容:** Docker Desktopを利用して、プロジェクトのDocker開発環境を構築し、起動します。これにより、必要な依存関係がコンテナ内に自動的にインストールされます。
755
+ - **指示:**
756
  1. Docker Desktopがインストールされ、起動していることを確認してください。
757
  2. プロジェクトのルートディレクトリで、以下のコマンドを実行してDockerコンテナをビルドし、バックグラウンドで起動します。
758
  ```bash
 
765
  - **内容:** 環境変数設定ファイル(`.env`)とそのテンプレート(`.env.example`)を作成します。
766
  - **指示:** プロジェクトのルートディレクトリに`.env`ファイルと`.env.example`ファイルを作成してください。
767
 
768
+ ### フェーズ1.5: CI/CD検証用サンプルアプリケーションの作成
769
+
770
+ **目的:** CI/CDパイプラインが全体として機能することを検証するための、最もシンプルな「Hello World」的なGradioアプリケーションを作成する。
771
+
772
+ - [ ] **中タスク1.5.1: Gradioサンプルコードの実装**
773
+ - [ ] **小タスク1.5.1.1 (RED):** `main.py`のテストを作成
774
+ - **担当:** AI
775
+ - **内容:** `tests/test_main.py`を作成し、`main.py`の`greet`関数が特定の文字列を返すことを期待するテストを記述します。この時点では`main.py`や`greet`関数が存在しないため、テストは失敗します。
776
+ - [ ] **小タスク1.5.1.2 (GREEN):** `main.py`にサンプルを実装
777
+ - **担当:** AI
778
+ - **内容:** `src/ai_api/main.py`に、簡単な`greet`関数と、それを呼び出すGradioインターフェースを実装し、テストをパスさせます。
779
+ - [ ] **小タスク1.5.1.3 (REFACTOR):** リファクタリング
780
+ - **担当:** AI
781
+ - **内容:** コードを整理し、可読性を高めます。
782
+
783
+ ### フェーズ2: CI/CDの構築とデプロイ
784
+
785
+ **目的:** コードの品質を自動的に検証し、Hugging Face Spacesへ自動的にデプロイする仕組みを構築する。
786
+
787
+ - [ ] **中タスク2.1: CIワークフローの構築 (GitHub Actions)**
788
+ - [ ] **小タスク2.1.1 (RED):** CI設定ファイルの骨格作成
789
+ - **担当:** AI
790
+ - **内容:** `.github/workflows/ci.yml` を作成します。最初はトリガーだけを記述し、具体的なジョブは空にしておきます。この時点では何も実行されません。
791
+ - [ ] **小タスク2.1.2 (GREEN):** CIジョブの実装
792
+ - **担当:** AI
793
+ - **内容:** `ci.yml` に、Pythonのセットアップ、依存関係のインストール、`ruff`によるlintチェック、`mypy`による型チェック、`pytest`によるテスト実行のステップを追加します。
794
+ - **指示:** `/home/jam/kids-playground-ai-api/.github/workflows/ci.yml` を更新してください。
795
+ - [ ] **小タスク2.1.3 (REFACTOR):** ワークフローの最適化
796
+ - **担当:** AI
797
+ - **内容:** キャッシュ機構などを導入し、CIの実行時間を短縮します。
798
+ - [ ] **小タスク2.1.4: CIの動作確認**
799
+ - **担当:** 人間
800
+ - **内容:** この変更をGitHubにプッシュし、GitHubの「Actions」タブでワークフローが正しく実行され、全てのチェックが成功することを確認します。
801
+
802
+ - [ ] **中タスク2.2: CDワークフローの構築 (GitHub Actions)**
803
+ - [ ] **小タスク2.2.1: Hugging Faceアクセストークンの準備**
804
+ - **担当:** 人間
805
+ - **内容:** Hugging Faceの設定ページで`write`権限を持つアクセストークンを発行し、それをGitHubリポジトリのSecretsに`HF_TOKEN`として登録します。
806
+ - [ ] **小タスク2.2.2 (RED):** デプロイジョブの骨格作成
807
+ - **担当:** AI
808
+ - **内容:** `ci.yml`に、`test`ジョブの成功後に`main`ブランチでのみ実行される`deploy-to-hf-space`ジョブを追加します。最初は簡単な`echo`コマンドのみを記述し、デプロイが実行されない状態にします。
809
+ - [ ] **小タスク2.2.3 (GREEN):** デ���ロイジョブの実装
810
+ - **担当:** AI
811
+ - **内容:** `deploy-to-hf-space`ジョブに、`hugging-face/push-to-hub`アクションを追加し、Secretsに登録した`HF_TOKEN`を使ってHugging Face Spacesにコードをプッシュするように実装します。
812
+ - [ ] **小タスク2.2.4: CDの動作確認**
813
+ - **担当:** 人間
814
+ - **内容:** CI/CDが成功したコミットを`main`ブランチにマージし、GitHubの「Actions」タブでデプロイジョブが成功することを確認します。その後、Hugging Face Spaceの公開URLにアクセスし、アプリケーションが正しくデプロイされていることを確認します。
815
 
816
+ ### フェーズ3: AIアプリケーションのTDD (コアロジック → API)
817
 
818
  **目的:** クリーンアーキテクチャの原則に従い、内側のビジネスロジックから外側のAPIへと実装を進める。
819
 
820
+ - [ ] **中タスク3.1: AIコアロジック `Summarizer` の実装**
821
+ - [ ] **小タスク3.1.1 (RED):** `Summarizer`クラスのテスト作成
822
  - **担当:** AI
823
  - **内容:** `tests/core/test_inference.py` を作成し、「`from src.ai_api.core.inference import Summarizer` が成功すること」をテストします。このテストは、ファイルやクラスが存在しないため失敗します。
824
+ - [ ] **小タスク3.1.2 (GREEN):** `Summarizer`クラスの骨格作成
825
  - **担当:** AI
826
  - **内容:** `src/ai_api/core/inference.py` と、空の`Summarizer`クラスを作成し、テストをパスさせます。
827
+ - [ ] **小タスク3.1.3 (REFACTOR):** リファクタリング
828
  - **担当:** AI
829
  - **内容:** この時点では特になし。コミットの区切りとします。
830
 
831
+ - [ ] **中タスク3.2: AI設定クラス `Config` の実装と注入**
832
+ - [ ] **小タスク3.2.1 (RED):** `Summarizer`が設定オブジェクトを受け取るテスト作成
833
  - **担当:** AI
834
  - **内容:** `tests/core/test_inference.py`に追記します。
835
  - **内容:** `Summarizer`がコンストラクタで設定オブジェクト(モデル名など)を受け取ることを期待するテストを`tests/core/test_inference.py`に追記します。
836
+ - [ ] **小タスク3.2.2 (GREEN):** 設定クラスの作成とコンストラクタ修正
837
  - **担当:** AI
838
  - **内容:** `src/ai_api/config.py`に設計通りの設定クラス(`ModelConfig`など)を作成します。`Summarizer`の`__init__`を修正し、設定オブジェクトを受け取るようにします。
839
+ - [ ] **小タスク3.2.3 (REFACTOR):** リファクタリング
840
  - **担当:** AI
841
  - **内容:** コードの可読性を向上させます。 **この時点で、AIモデルを切り替えるための基本的な仕組み(設定値を外部から与える)が完成します。**
842
 
843
+ - [ ] **中タスク3.3: 要約機能 `summarize` メソッドの実装**
844
+ - [ ] **小タスク3.3.1 (RED):** `summarize`メソッドのユニットテスト作成
845
  - **担当:** AI
846
  - **内容:** `unittest.mock.patch`を使い、`transformers.pipeline`をモック(偽物に差し替え)します。「`summarize`メソッドを呼ぶと、内部で`pipeline`が特定の引数で呼ばれ、モックの返り値がそのまま返されること」をテストします。これにより、重いモデルをロードせずにロジックだけを高速にテストできます。
847
+ - [ ] **小タスク3.3.2 (GREEN):** `summarize`メソッドの実装
848
  - **担当:** AI
849
  - **内容:** `Summarizer`クラスに`summarize`メソッドを実装し、内部で`transformers.pipeline`を呼び出して要約を実行するようにします。
850
+ - [ ] **小タスク3.3.3 (REFACTOR):** リファクタリング
851
  - **担当:** AI
852
  - **内容:** エラーハンドリングなどを追加し、コードを整理します。
853
 
854
+ - [ ] **中タスク3.4: APIエントリーポイント `main.py` の実装**
855
+ - [ ] **小タスク3.4.1 (RED):** APIのインテグレーションテスト作成
856
  - **担当:** AI
857
  - **内容:** `tests/test_api.py`を作成します。テスト内でGradioアプリを別スレッドで起動し、`requests.post`で`/api/predict/`にリクエストを送信して、期待した応答が得られない(サーバーがないため)ことを確認します。
858
+ - [ ] **小タスク3.4.2 (GREEN):** `main.py`の実装
859
  - **担当:** AI
860
  - **内容:** `src/ai_api/main.py`を作成します。`Summarizer`と設定クラスをインスタンス化し、DI(依存性の注入)してGradioの`Interface`を定義・起動します。
861
+ - [ ] **小タスク3.4.3 (REFACTOR):** リファクタリング
862
  - **担当:** AI
863
  - **内容:** コードを整理します。
864
+ - [ ] **小タスク3.4.4: 手動での動作確認**
865
  - **担当:** 人間
866
  - **内容:** `python src/ai_api/main.py` を実行し、ブラウザで表示されるGradioのUIにテキストを入力して、要約機能が単体で正しく動作することを確認します。
867
 
868
+ ### フェーズ4: Djangoへの組み込み
869
 
870
  **目的:** 独立して動作するAIアプリケーションを、DjangoからAPI経由で安全に呼び出す。
871
 
872
+ - [ ] **中タスク4.1: Django側のAPIクライアント実装**
873
+ - [ ] **小タスク4.1.1 (RED):** APIクライアントのテスト作成
874
  - **担当:** AI
875
  - **内容:** `myapp/tests/test_clients.py`を作成します。`requests.post`がモック化されている状態でAPIクライアント関数を呼び出し、成功時・タイムアウト時・サーバーエラー時の挙動をテストします。
876
+ - [ ] **小タスク4.1.2 (GREEN):** APIクライアントの実装
877
  - **担当:** AI
878
  - **内容:** `myapp/clients/ai_summary_client.py`を作成し、`requests`を使って外部APIを呼び出す関数を実装します。
879
+ - [ ] **小タスク4.1.3 (REFACTOR):** リファクタリング
880
  - **担当:** AI
881
  - **内容:** 設定を`settings.py`から読み込むようにするなど、コードを整理します。
882
 
883
+ - [ ] **中タスク4.2: Django Viewの実装**
884
+ - [ ] **小タスク4.2.1 (RED):** ViewのURLテスト作成
885
  - **担当:** AI
886
  - **内容:** `myapp/tests/test_views.py`に、`/summarize/playground/{id}/`へのGETリクエストが404を返すテストを書きます。
887
+ - [ ] **小タスク4.2.2 (GREEN):** URLとViewの骨格作成
888
  - **担当:** AI
889
  - **内容:** `myapp/urls.py`と`myapp/views/summary_views.py`を作成・編集し、テストをパスさせます。
890
+ - [ ] **小タスク4.2.3 (RED):** Viewとクライアントの連携テスト作成
891
  - **担当:** AI
892
  - **内容:** `unittest.mock.patch`でAPIクライアントをモック化し、「Viewを呼び出すと、内部でAPIクライアントが特定の引数で呼ばれること」をテストします。
893
+ - [ ] **小タスク4.2.4 (GREEN):** Viewロジックの実装
894
  - **担当:** AI
895
  - **内容:** View内で口コミの取得・検証ロジック、およびAPIクライアントの呼び出しを実装します。
896
+ - [ ] **小タスク4.2.5 (REFACTOR):** リファクタリング
897
  - **担当:** AI
898
  - **内容:** コードを整理します。
899
 
900
+ - [ ] **中タスク4.3: 統合テスト**
901
+ - [ ] **小タスク4.3.1: 手動での最終確認**
902
  - **担当:** 人間
903
  - **内容:** DjangoサーバーとAIアプリ(Gradio)を両方ローカルで起動し、ブラウザから最初の要約ボタンをクリックして、全体の流れが正しく動作するかを確認します。
904
 
905
+ ```