Spaces:
Sleeping
Sleeping
Commit
·
d270dd6
1
Parent(s):
5e60243
CICDのタスク追加
Browse files- 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):**
|
| 193 |
-
2. **CD (
|
| 194 |
|
| 195 |
### 6.2. 設定
|
| 196 |
-
- **GitHub Actions:** `.github/workflows/ci.yml
|
| 197 |
-
- **Hugging Face Hub:**
|
|
|
|
|
|
|
|
|
|
| 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__\
|
| 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 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 770 |
|
| 771 |
-
### フェーズ
|
| 772 |
|
| 773 |
**目的:** クリーンアーキテクチャの原則に従い、内側のビジネスロジックから外側のAPIへと実装を進める。
|
| 774 |
|
| 775 |
-
- [ ] **中タスク
|
| 776 |
-
- [ ] **小タスク
|
| 777 |
- **担当:** AI
|
| 778 |
- **内容:** `tests/core/test_inference.py` を作成し、「`from src.ai_api.core.inference import Summarizer` が成功すること」をテストします。このテストは、ファイルやクラスが存在しないため失敗します。
|
| 779 |
-
- [ ] **小タスク
|
| 780 |
- **担当:** AI
|
| 781 |
- **内容:** `src/ai_api/core/inference.py` と、空の`Summarizer`クラスを作成し、テストをパスさせます。
|
| 782 |
-
- [ ] **小タスク
|
| 783 |
- **担当:** AI
|
| 784 |
- **内容:** この時点では特になし。コミットの区切りとします。
|
| 785 |
|
| 786 |
-
- [ ] **中タスク
|
| 787 |
-
- [ ] **小タスク
|
| 788 |
- **担当:** AI
|
| 789 |
- **内容:** `tests/core/test_inference.py`に追記します。
|
| 790 |
- **内容:** `Summarizer`がコンストラクタで設定オブジェクト(モデル名など)を受け取ることを期待するテストを`tests/core/test_inference.py`に追記します。
|
| 791 |
-
- [ ] **小タスク
|
| 792 |
- **担当:** AI
|
| 793 |
- **内容:** `src/ai_api/config.py`に設計通りの設定クラス(`ModelConfig`など)を作成します。`Summarizer`の`__init__`を修正し、設定オブジェクトを受け取るようにします。
|
| 794 |
-
- [ ] **小タスク
|
| 795 |
- **担当:** AI
|
| 796 |
- **内容:** コードの可読性を向上させます。 **この時点で、AIモデルを切り替えるための基本的な仕組み(設定値を外部から与える)が完成します。**
|
| 797 |
|
| 798 |
-
- [ ] **中タスク
|
| 799 |
-
- [ ] **小タスク
|
| 800 |
- **担当:** AI
|
| 801 |
- **内容:** `unittest.mock.patch`を使い、`transformers.pipeline`をモック(偽物に差し替え)します。「`summarize`メソッドを呼ぶと、内部で`pipeline`が特定の引数で呼ばれ、モックの返り値がそのまま返されること」をテストします。これにより、重いモデルをロードせずにロジックだけを高速にテストできます。
|
| 802 |
-
- [ ] **小タスク
|
| 803 |
- **担当:** AI
|
| 804 |
- **内容:** `Summarizer`クラスに`summarize`メソッドを実装し、内部で`transformers.pipeline`を呼び出して要約を実行するようにします。
|
| 805 |
-
- [ ] **小タスク
|
| 806 |
- **担当:** AI
|
| 807 |
- **内容:** エラーハンドリングなどを追加し、コードを整理します。
|
| 808 |
|
| 809 |
-
- [ ] **中タスク
|
| 810 |
-
- [ ] **小タスク
|
| 811 |
- **担当:** AI
|
| 812 |
- **内容:** `tests/test_api.py`を作成します。テスト内でGradioアプリを別スレッドで起動し、`requests.post`で`/api/predict/`にリクエストを送信して、期待した応答が得られない(サーバーがないため)ことを確認します。
|
| 813 |
-
- [ ] **小タスク
|
| 814 |
- **担当:** AI
|
| 815 |
- **内容:** `src/ai_api/main.py`を作成します。`Summarizer`と設定クラスをインスタンス化し、DI(依存性の注入)してGradioの`Interface`を定義・起動します。
|
| 816 |
-
- [ ] **小タスク
|
| 817 |
- **担当:** AI
|
| 818 |
- **内容:** コードを整理します。
|
| 819 |
-
- [ ] **小タスク
|
| 820 |
- **担当:** 人間
|
| 821 |
- **内容:** `python src/ai_api/main.py` を実行し、ブラウザで表示されるGradioのUIにテキストを入力して、要約機能が単体で正しく動作することを確認します。
|
| 822 |
|
| 823 |
-
### フェーズ
|
| 824 |
|
| 825 |
**目的:** 独立して動作するAIアプリケーションを、DjangoからAPI経由で安全に呼び出す。
|
| 826 |
|
| 827 |
-
- [ ] **中タスク
|
| 828 |
-
- [ ] **小タスク
|
| 829 |
- **担当:** AI
|
| 830 |
- **内容:** `myapp/tests/test_clients.py`を作成します。`requests.post`がモック化されている状態でAPIクライアント関数を呼び出し、成功時・タイムアウト時・サーバーエラー時の挙動をテストします。
|
| 831 |
-
- [ ] **小タスク
|
| 832 |
- **担当:** AI
|
| 833 |
- **内容:** `myapp/clients/ai_summary_client.py`を作成し、`requests`を使って外部APIを呼び出す関数を実装します。
|
| 834 |
-
- [ ] **小タスク
|
| 835 |
- **担当:** AI
|
| 836 |
- **内容:** 設定を`settings.py`から読み込むようにするなど、コードを整理します。
|
| 837 |
|
| 838 |
-
- [ ] **中タスク
|
| 839 |
-
- [ ] **小タスク
|
| 840 |
- **担当:** AI
|
| 841 |
- **内容:** `myapp/tests/test_views.py`に、`/summarize/playground/{id}/`へのGETリクエストが404を返すテストを書きます。
|
| 842 |
-
- [ ] **小タスク
|
| 843 |
- **担当:** AI
|
| 844 |
- **内容:** `myapp/urls.py`と`myapp/views/summary_views.py`を作成・編集し、テストをパスさせます。
|
| 845 |
-
- [ ] **小タスク
|
| 846 |
- **担当:** AI
|
| 847 |
- **内容:** `unittest.mock.patch`でAPIクライアントをモック化し、「Viewを呼び出すと、内部でAPIクライアントが特定の引数で呼ばれること」をテストします。
|
| 848 |
-
- [ ] **小タスク
|
| 849 |
- **担当:** AI
|
| 850 |
- **内容:** View内で口コミの取得・検証ロジック、およびAPIクライアントの呼び出しを実装します。
|
| 851 |
-
- [ ] **小タスク
|
| 852 |
- **担当:** AI
|
| 853 |
- **内容:** コードを整理します。
|
| 854 |
|
| 855 |
-
- [ ] **中タスク
|
| 856 |
-
- [ ] **小タスク
|
| 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 |
+
```
|