Spaces:
Sleeping
Sleeping
Commit
·
af07d37
0
Parent(s):
Initial commit with .gitignore
Browse files- .github/workflows/ci.yml +0 -0
- .gitignore +46 -0
- Dockerfile +0 -0
- README.md +0 -0
- docs/ai_api_development_guide.md +802 -0
- pyproject.toml +0 -0
- requirements.txt +0 -0
.github/workflows/ci.yml
ADDED
|
File without changes
|
.gitignore
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Byte-compiled / optimized / DLL files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
*.pyd
|
| 5 |
+
*.pyo
|
| 6 |
+
|
| 7 |
+
# C extensions
|
| 8 |
+
*.so
|
| 9 |
+
|
| 10 |
+
# Distribution / packaging
|
| 11 |
+
.Python
|
| 12 |
+
build/
|
| 13 |
+
dist/
|
| 14 |
+
eggs/
|
| 15 |
+
*.egg
|
| 16 |
+
*.egg-info/
|
| 17 |
+
|
| 18 |
+
# Editors
|
| 19 |
+
.idea/
|
| 20 |
+
.vscode/
|
| 21 |
+
*.sublime-project
|
| 22 |
+
*.sublime-workspace
|
| 23 |
+
|
| 24 |
+
# Virtual environment
|
| 25 |
+
venv/
|
| 26 |
+
.venv/
|
| 27 |
+
|
| 28 |
+
# Logs and databases
|
| 29 |
+
*.log
|
| 30 |
+
*.sqlite3
|
| 31 |
+
*.db
|
| 32 |
+
|
| 33 |
+
# OS generated files
|
| 34 |
+
.DS_Store
|
| 35 |
+
Thumbs.db
|
| 36 |
+
|
| 37 |
+
# Environment variables
|
| 38 |
+
.env
|
| 39 |
+
|
| 40 |
+
# Testing
|
| 41 |
+
.pytest_cache/
|
| 42 |
+
htmlcov/
|
| 43 |
+
.coverage
|
| 44 |
+
|
| 45 |
+
# Hugging Face
|
| 46 |
+
hf_cache/
|
Dockerfile
ADDED
|
File without changes
|
README.md
ADDED
|
File without changes
|
docs/ai_api_development_guide.md
ADDED
|
@@ -0,0 +1,802 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AI API 開発ガイド
|
| 2 |
+
|
| 3 |
+
このドキュメントは、Hugging Face SpacesとGradioを利用したAI APIの開発環境構築と、その後の開発プロセスに関する要点をまとめたものです。
|
| 4 |
+
|
| 5 |
+
## 1. 概要
|
| 6 |
+
|
| 7 |
+
### 1.1. 目的と機能概要
|
| 8 |
+
|
| 9 |
+
本プロジェクトの目的は、「親子で遊ぼうナビ」にAIを活用した**口コミの自動要約機能**を実装することです。
|
| 10 |
+
|
| 11 |
+
- **目的:** ユーザーが多数の口コミを全て読んでも、施設の全体的な評判を素早く、かつ客観的に把握できるようにする。
|
| 12 |
+
- **ユーザー体験:**
|
| 13 |
+
1. ユーザーは施設の詳細ページで「口コミをAI要約」ボタンをクリックします。
|
| 14 |
+
2. AIがその施設の全口コミを分析し、「ポジティブな点」と「注意が必要な点」などをまとめた中立的な要約文を生成します。
|
| 15 |
+
3. 生成された要約がモーダルウィンドウ等で表示され、ユーザーは短時間で施設の長所と短所を理解できます。
|
| 16 |
+
|
| 17 |
+
### 1.2. アーキテクチャ概要
|
| 18 |
+
|
| 19 |
+
この機能は、Djangoアプリケーションと、Hugging Face Spaces上で動作するGradio APIとの連携によって実現します。
|
| 20 |
+
|
| 21 |
+
- **開発環境:** Dockerコンテナ内で開発・テストを行う。
|
| 22 |
+
- **バージョン管理:** Gitでコードを管理する。
|
| 23 |
+
- **CI/CD:** GitHub Actionsでテストとデプロイを自動化する。
|
| 24 |
+
- **本番環境:** Hugging Face Spacesにデプロイし、APIを公開する。
|
| 25 |
+
|
| 26 |
+
### 1.3. 技術選定理由
|
| 27 |
+
|
| 28 |
+
- **Hugging Face Spaces:**
|
| 29 |
+
- **選定理由:** 無料枠が利用可能で、迅速なプロトタイピングに適しています。また、GitHubリポジトリと連携した自動デプロイ機能(CI/CD)が標準で提供されており、開発体験が非常にスムーズです。
|
| 30 |
+
- **代替案との比較:** AWS LambdaやGoogle Cloud Functionsのようなサーバーレス環境も考えられますが、これらはコンテナイメージのサイズ制限が厳しく、大規模なAIモデルのデプロイには追加の工夫が必要です。Hugging Face Inference APIは最も手軽ですが、カスタムロジックの追加やUIの提供ができないため、今回はGradioと組み合わせられるSpacesを選択しました。
|
| 31 |
+
- **Gradio:**
|
| 32 |
+
- **選定理由:** 数行のコードでAIモデルのデモUIとAPIエンドポイントを同時に作成できるため、開発速度を大幅に向上させます。特に、動作確認用のUIが自動で生成される点は、開発初期段階での実験やデバッグにおいて大きな利点となります。
|
| 33 |
+
|
| 34 |
+
### 1.4. アーキテクチャ図
|
| 35 |
+
|
| 36 |
+
```mermaid
|
| 37 |
+
graph TD
|
| 38 |
+
subgraph "ユーザー環境"
|
| 39 |
+
Browser[ユーザーのブラウザ]
|
| 40 |
+
end
|
| 41 |
+
|
| 42 |
+
subgraph "Webサーバー (Django)"
|
| 43 |
+
A[Django View] -- DBから口コミ取得 --> DB[(PostgreSQL)]
|
| 44 |
+
A -- 要約リクエスト --> B{API Client}
|
| 45 |
+
B -- HTTP POST --> C[AI API Gateway]
|
| 46 |
+
end
|
| 47 |
+
|
| 48 |
+
subgraph "AI推論環境 (Hugging Face Spaces)"
|
| 49 |
+
C -- 認証・ルーティング --> D[Gradio App]
|
| 50 |
+
D -- 推論実行 --> E[Summarization Model]
|
| 51 |
+
end
|
| 52 |
+
|
| 53 |
+
Browser -- "1. 要約ボタンクリック" --> A
|
| 54 |
+
C -- "3. 要約結果 (JSON)" --> B
|
| 55 |
+
A -- "4. 要約結果 (JSON)" --> Browser
|
| 56 |
+
|
| 57 |
+
style DB fill:#f9f,stroke:#333,stroke-width:2px
|
| 58 |
+
style E fill:#ccf,stroke:#333,stroke-width:2px
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
---
|
| 62 |
+
|
| 63 |
+
## 2. プロジェクト構造と開発環境
|
| 64 |
+
|
| 65 |
+
保守性・拡張性を高めるため、役割ごとにファイルを分割したディレクトリ構造を採用し、Dockerで開発環境を構築します。
|
| 66 |
+
|
| 67 |
+
### 2.1. 推奨ディレクトリ構造
|
| 68 |
+
|
| 69 |
+
```
|
| 70 |
+
kids-playground-ai-api/
|
| 71 |
+
│
|
| 72 |
+
├── .github/
|
| 73 |
+
│ └── workflows/
|
| 74 |
+
│ └── ci.yml
|
| 75 |
+
│
|
| 76 |
+
├── .gitignore
|
| 77 |
+
├── Dockerfile
|
| 78 |
+
├── pyproject.toml
|
| 79 |
+
├── requirements.txt
|
| 80 |
+
├── README.md
|
| 81 |
+
│
|
| 82 |
+
├── docs/
|
| 83 |
+
│ └── ai_api_development_guide.md # ★この開発ガイド
|
| 84 |
+
│
|
| 85 |
+
├── src/
|
| 86 |
+
│ └── ai_api/
|
| 87 |
+
│ ├── __init__.py
|
| 88 |
+
│ ├── main.py # APIエントリーポイント (Gradio UI)
|
| 89 |
+
│ ├── core/
|
| 90 |
+
│ │ ├── __init__.py
|
| 91 |
+
│ │ └── inference.py # AI推論ロジック
|
| 92 |
+
│ └── config.py # 設定ファイル
|
| 93 |
+
│
|
| 94 |
+
└── tests/
|
| 95 |
+
└── core/
|
| 96 |
+
└── test_inference.py
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
### 2.2. 品質管理ツールの設定
|
| 100 |
+
|
| 101 |
+
- **`pyproject.toml`:** プロジェクトルートに作成し、Ruff (フォーマッター/リンター), Mypy (型チェッカー), Pytest (テストフレームワーク) の設定を記述します。
|
| 102 |
+
- **`.pre-commit-config.yaml`:** `pre-commit`を導入し、Gitコミット時に自動でコードチェックが走るように設定します。
|
| 103 |
+
|
| 104 |
+
### 2.3. 開発環境 (Docker)
|
| 105 |
+
|
| 106 |
+
- **`requirements.txt`:** 必要なライブラリを記述します。
|
| 107 |
+
- **`Dockerfile`:** ローカル開発環���の統一と効率化のために使用します。
|
| 108 |
+
- **注記:** この`Dockerfile`は、あくまでローカル開発用です。デプロイ先のHugging Face Spacesでは、`Dockerfile`は直接使われず、`requirements.txt`に基づいて環境が自動構築されます。
|
| 109 |
+
- **`docker-compose.yml`:** DjangoサーバーとAI APIサーバーなど、複数のサービスを定義し、一括で起動・管理するために使用します。
|
| 110 |
+
- **Docker Desktopの活用:** WindowsやMacのユーザーは、Docker Desktopを利用することで、コンテナの状態をGUIで視覚的に確認したり、起動・停止を容易に行うことができます。Linuxユーザーも利用可能です。コマンドライン操作に慣れていない開発者には、Docker Desktopの利用を推奨します。
|
| 111 |
+
|
| 112 |
+
#### 2.3.1. ローカル環境の起動とアクセス
|
| 113 |
+
|
| 114 |
+
開発を開始するには、プロジェクトのルートディレクトリで以下のコマンドを実行します。Docker Desktopを利用している場合は、GUI上から `docker-compose.yml` を指定して起動することも可能です。
|
| 115 |
+
|
| 116 |
+
```bash
|
| 117 |
+
|
| 118 |
+
# -d フラグでバックグラウンドで起動
|
| 119 |
+
docker-compose up --build -d
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
これにより、各サービスがコンテナとして起動します。
|
| 123 |
+
- **Djangoアプリケーション:** `http://localhost:8000`
|
| 124 |
+
- **AI API (Gradio):** `http://localhost:7860`
|
| 125 |
+
|
| 126 |
+
### 2.4. デバッグ方法
|
| 127 |
+
|
| 128 |
+
コンテナ内で問題が発生した場合、以下のコマンドでコンテナの内部に入り、デバッグ作業を行うことができます。
|
| 129 |
+
|
| 130 |
+
```bash
|
| 131 |
+
|
| 132 |
+
# <service_name> は docker-compose.yml で定義したサービス名 (例: web, api)
|
| 133 |
+
docker-compose exec <service_name> bash
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
コンテナ内では、ログファイルの確認、Pythonのインタラクティブシェルを起動してのコード実行などが可能です。
|
| 137 |
+
|
| 138 |
+
---
|
| 139 |
+
|
| 140 |
+
## 3. モデル管理
|
| 141 |
+
|
| 142 |
+
- **モデル選定:** まずは速度とリソースのバランスが良い軽量なモデル(例: `llm-jp/t5-small-japanese-finetuned-sum`)で開発を開始し、必要に応じて、より高品質なモデル(例: `izumi-lab/t5-base-japanese-summary`)への差し替えを検討します。
|
| 143 |
+
- **情報記録:** `config.py`には、モデル名だけでなく、モデルサイズ、ライセンス、推論速度の目安などの情報もコメントとして記録し、管理します。
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## 4. 実装の役割分担
|
| 148 |
+
|
| 149 |
+
- **`src/ai_api/config.py` (設定担当):** モデルやパラメータの情報を管理します。
|
| 150 |
+
- **`src/ai_api/core/inference.py` (AI推論担当):** AIモデルのロードと推論のコアロジックを実装します。
|
| 151 |
+
- **`src/ai_api/main.py` (API受付担当):** GradioのUIを定義し、サーバーを起動します。Dockerコンテナ内で外部にAPIを公開するため、`iface.launch(server_name="0.0.0.0")`のように起動オプションを指定します。
|
| 152 |
+
|
| 153 |
+
### AI新機能開発におけるコーディング規約
|
| 154 |
+
|
| 155 |
+
AI新機能の開発においては、以下のコーディング規約と開発原則を遵守し、高品質で保守性の高いコードベースを目指します。
|
| 156 |
+
|
| 157 |
+
#### 1. Pythonコーディング規約
|
| 158 |
+
|
| 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を記述し、コードの意図と振る舞いを明確にします。
|
| 166 |
+
* **エラーハンドリング**: 予期せぬエラーや例外処理は、Djangoの標準的なエラーハンドリングやPythonの例外処理メカニズムに従い、適切にログを出力し、システムの安定性を確保します。
|
| 167 |
+
* **保守性と可読性**: コードは常に保守性と可読性を最優先に設計・実装します。複雑なロジックは小さな関数に分割し、変数名や関数名は意図が明確に伝わるように命名します。
|
| 168 |
+
* **単一責務の原則 (SRP)**: クラスや関数は、変更の理由が一つであるように設計します。これにより、コードの凝集度を高め、テスト容易性と再利用性を向上させます。
|
| 169 |
+
|
| 170 |
+
#### 2. テスト駆動開発 (TDD) とテストの考え方
|
| 171 |
+
|
| 172 |
+
* **t_wada氏のTDDスタイル**: 開発は「Red → Green → Refactor」のTDDサイクルを厳守して進めます。
|
| 173 |
+
* **Red**: 最初に失敗するテストを記述し、必要な機能の振る舞いを定義します。
|
| 174 |
+
* **Green**: テストが成功する最小限のコードを実装します。
|
| 175 |
+
* **Refactor**: コードの品質を向上させ、重複を排除し、設計を改善します。
|
| 176 |
+
* **「動く仕様書」としてのテスト**: テストコードは、単なる品質保証の手段ではなく、機能の振る舞いを明確に記述した「動く仕様書」として機能するように設計します。
|
| 177 |
+
* テストケース名(`pytest`のテスト関数名など)は、**日本語で**「〜という状況で、〜という振る舞いをすべき」というように、具体的なシナリオと期待される結果を記述します。
|
| 178 |
+
* テストは実装の詳細ではなく、機能の**振る舞い(Behavior)**に焦点を当てます。
|
| 179 |
+
|
| 180 |
+
---
|
| 181 |
+
|
| 182 |
+
## 5. テスト戦略
|
| 183 |
+
|
| 184 |
+
- **ユニットテスト:** `pytest`を使い、`inference.py`内の純粋な関数(AIのコアロジック)をテストします。
|
| 185 |
+
- **インテグレーションテスト:** ローカルで起動したGradioサーバーに対し、`requests`ライブラリで実際にAPIリクエストを送り、HTTPステータスコードやレスポンスの形式が期待通りであることを確認するテストも追加します。これにより、APIとしての正常性を保証します。
|
| 186 |
+
|
| 187 |
+
---
|
| 188 |
+
|
| 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 |
+
|
| 201 |
+
## 7. セキュリティと利用制限
|
| 202 |
+
|
| 203 |
+
### 7.1. API認証
|
| 204 |
+
|
| 205 |
+
**課題:** Hugging Face Spacesで公開されるAPIは、デフォルトでは誰でもアクセス可能な状態になります。意図しない利用や攻撃を防ぐため、Djangoアプリケーションからのみリクエストを受け付けるように制御する必要があります。
|
| 206 |
+
|
| 207 |
+
**対策:** APIキーによる認証を導入します。
|
| 208 |
+
1. **APIキーの生成:** UUIDなどで推測困難な文字列をAPIキーとして生成します。
|
| 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 |
+
|
| 216 |
+
### 7.2. その他の対策
|
| 217 |
+
|
| 218 |
+
- **Abuse対策:** 公開APIが悪用されるのを防ぐため、Gradioの`queue()`メソッドを利用してリクエストを待ち行列に入れ、同時アクセス数を制限することを検討します。
|
| 219 |
+
- **免責事項:** `README.md`に、APIの利用は自己責任であること、生成される内容の正確性を保証しないこと、商用利用に関する制限などを明記しておきます。
|
| 220 |
+
|
| 221 |
+
---
|
| 222 |
+
|
| 223 |
+
## 8. 今後の開発プロセス
|
| 224 |
+
|
| 225 |
+
このドキュメントは、今後の調査や開発の進捗に応じて、継続的に更新・メンテナンスされます。
|
| 226 |
+
|
| 227 |
+
---
|
| 228 |
+
|
| 229 |
+
## 9. 設計
|
| 230 |
+
|
| 231 |
+
このセクションでは、機能実装の前に定義するべき、より詳細な設計について記録します。
|
| 232 |
+
|
| 233 |
+
### 9.1. APIインターフェース設計 (口コミ要約機能 v1)
|
| 234 |
+
|
| 235 |
+
DjangoとGradio APIがやり取りするデータ形式とルールを以下のように定めます。
|
| 236 |
+
|
| 237 |
+
#### 9.1.1. 基��方針
|
| 238 |
+
- **通信プロトコル:** HTTP/HTTPS
|
| 239 |
+
- **データ形式:** JSON
|
| 240 |
+
- **基本構造:** Gradioの標準API形式に準拠します。
|
| 241 |
+
|
| 242 |
+
#### 9.1.2. リクエスト仕様 (Django → Gradio API)
|
| 243 |
+
- **エンドポイント:** `(SpaceのURL)/api/predict/`
|
| 244 |
+
- **HTTPメソッド:** `POST`
|
| 245 |
+
- **ボディ (JSON):**
|
| 246 |
+
```json
|
| 247 |
+
{
|
| 248 |
+
"data": [
|
| 249 |
+
"口コミ全文を結合した文字列..."
|
| 250 |
+
]
|
| 251 |
+
}
|
| 252 |
+
```
|
| 253 |
+
|
| 254 |
+
#### 9.1.3. レスポンス仕様 (Gradio API → Django)
|
| 255 |
+
**成功時 (HTTP 200 OK):**
|
| 256 |
+
- **ボディ (JSON):**
|
| 257 |
+
```json
|
| 258 |
+
{
|
| 259 |
+
"data": [
|
| 260 |
+
"AIによって生成された要約文..."
|
| 261 |
+
],
|
| 262 |
+
"duration": 3.5
|
| 263 |
+
}
|
| 264 |
+
```
|
| 265 |
+
|
| 266 |
+
**失敗時 (HTTP 500 Internal Server Error):**
|
| 267 |
+
- **ボディ (JSON):**
|
| 268 |
+
```json
|
| 269 |
+
{
|
| 270 |
+
"error": "Gradio側で設定したエラーメッセージ"
|
| 271 |
+
}
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
### 9.2. UI/UX設計 (口コミ要約機能 v1)
|
| 275 |
+
|
| 276 |
+
ユーザーが機能を直感的に利用でき、システムの応答を快適に待てるように、以下の通りUI/UXを設計します。
|
| 277 |
+
|
| 278 |
+
#### 9.2.1. 操作フロー
|
| 279 |
+
1. **トリガー:** ユーザーが施設詳細ページの「口コミをAI要約」ボタンをクリックします。
|
| 280 |
+
2. **ローディング:** ボタンが無効化され、「生成中です...」というテキストとスピナー(回転するアイコン)が表示されます。これにより、処理中であることがユーザーに明確に伝わります。
|
| 281 |
+
3. **結果表示:** 要約が完了すると、**Bootstrapのモーダルウィンドウ**が画面中央に表示され、その中に生成された要約文が提示されます。
|
| 282 |
+
4. **完了:** ユーザーはモーダルを閉じて、元のページ閲覧を続けます。ローディング表示は元のボタン表示に戻ります。
|
| 283 |
+
|
| 284 |
+
#### 9.2.2. エッジケースの対応
|
| 285 |
+
- **口コミが少ない場合:**
|
| 286 |
+
- **条件:** Django側で、対象施設の口コミが3件未満の場合。
|
| 287 |
+
- **処理:** AIのAPIは呼び出さず、即座に「口コミが3件未満のため、要約できません。」というアラートメッセージを表示します。これにより、不要なAPIコールを防ぎ、ユーザーに状況を的確に伝えます。
|
| 288 |
+
- **APIエラー発生時:**
|
| 289 |
+
- **条件:** APIのタイムアウトやサーバーエラーが発生した場合。
|
| 290 |
+
- **処理:** 「AIサーバーで問題が発生しました。時間をおいて再度お試しください。」といった内容をアラートまたはモーダルで表示します。
|
| 291 |
+
|
| 292 |
+
### 9.3. データ処理・ビジネスロジック設計 (v1)
|
| 293 |
+
|
| 294 |
+
AIの性能を最大限に引き出し、安定した運用を行うための内部ルールを以下のように設計します。
|
| 295 |
+
|
| 296 |
+
#### 9.3.1. 入力データの前処理 (Django側)
|
| 297 |
+
- **口コミの結合:** 複数の口コミは、それぞれを独立した段落としてAIに認識させるため、2つの改行文字 (`\n\n`) で区切って1つのテキストに結合します。
|
| 298 |
+
- **ノイズ除去:** 絵文字やURLなど、要約のノイズとなりうる不要な文字列は、正規表現を用いて事前に除去します。
|
| 299 |
+
|
| 300 |
+
#### 9.3.2. 要約実行の判断ロジック (Django側)
|
| 301 |
+
以下の条件を満たさない場合は、APIを呼び出さずにエラーとして処理します。
|
| 302 |
+
- **最小口コミ件数:** 3件以上
|
| 303 |
+
- **最小総文字数:** 全体の文字数が300文字以上
|
| 304 |
+
|
| 305 |
+
#### 9.3.3. AIモデルの推論パラメータ (Gradio API側)
|
| 306 |
+
生成される要約文の品質を制御するため、以下の初期パラメータを設定します。これらの値は `config.py` で管理し、調整可能にします。
|
| 307 |
+
- **要約文の最小長 (`min_length`):** 50
|
| 308 |
+
- **要約文の最大長 (`max_length`):** 250
|
| 309 |
+
- **長さペナルティ (`length_penalty`):** 2.0 (冗長な表現を抑制)
|
| 310 |
+
|
| 311 |
+
#### 9.3.4. 大量データへの対応方針
|
| 312 |
+
- **初期実装:** まずは全ての口コミを結合してAPIに送信します。モデルの最大入力長を超える場合は、`truncation=True` オプションにより自動的に末尾が切り捨てられます。
|
| 313 |
+
- **将来的な改善:** 性能やコストに問題が見られた場合、「直近1年間の口コミのみを対象とする」などの制限を後から追加することを検討します。
|
| 314 |
+
|
| 315 |
+
### 9.4. エラーハンドリング設計 (v1)
|
| 316 |
+
|
| 317 |
+
予期せぬ事態が発生した場合でもシステムが安定して動作し、ユーザーに適切なフィードバックを返せるよう、以下の通りエラーハンドリングを設計します。
|
| 318 |
+
|
| 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 |
+
|
| 339 |
+
### 9.5. 詳細設計: AI推論コア (`core/inference.py`) (v1)
|
| 340 |
+
|
| 341 |
+
AI推論のコアロジックは、保守性とテスト容易性を高めるために、いくつかの設計原則とデザインパターンを適用して構造化します。
|
| 342 |
+
|
| 343 |
+
#### 9.5.1. クラス設計と責務
|
| 344 |
+
- **`Summarizer` クラスの導入:** AIの推論に関連する全てのロジックを、単一の`Summarizer`クラスに集約します。このクラスは**「AIモデルを管理し、テキスト要約を実行する」**という明確な責務を持ちます。
|
| 345 |
+
|
| 346 |
+
#### 9.5.2. 適用するデザインパターン
|
| 347 |
+
- **ファサード (Facade) パターン:** `Summarizer`クラスは、`transformers`ライブラリの複雑な内部処理(モデルのロード、トークナイズ、推論、デコード等)をカプセル化(隠蔽)します。そして、`summarize(text)`という非常にシンプルなメソッドのみを外部に公開します。これにより、利用側(`main.py`)はAIの複雑な詳細を意識することなく、簡単かつ安全に要約機能を利用できます。
|
| 348 |
+
|
| 349 |
+
- **依存性の注入 (Dependency Injection) によるインスタンス管理:** AIモデルのようなリソースを大量に消費するオブジェクトは、リクエストごとに生成するべきではありません。代わりに、アプリケーションの起動時に一度だけ`Summarizer`のインスタンスを生成し、それを必要とする各コンポーネント(APIのエンドポイント関数など)に**注入(引数として渡す)**します。
|
| 350 |
+
- **なぜシングルトンを避けるか:** ご指摘の通り、グローバルな単一インスタンス(シングルトン)に依存する設計は、コンポーネント間の結合を強め、テストを困難にするためアンチパターンと見なされます。このアプローチは避けるべきです。
|
| 351 |
+
- **具体的な実現方法:** アプリケーションのエントリーポイント(`main.py`)で`Summarizer`インスタンスを生成し、`functools.partial`などを用いて、APIを処理する関数にそのインスタンスをあらかじめ渡しておくことで、グローバルな状態を持つことなくインスタンスの共有を実現します。これにより、テスト容易性と設計の柔軟性が大幅に向上します。
|
| 352 |
+
- **設定値の注入:** このDIパターンは、`Summarizer`クラスが使用するモデル名や要約の長さといった設定値をコンストラクタを通じて外部の`config`モジュールから受け取るという、元々の依存性注入の考え方とも一致しています。
|
| 353 |
+
|
| 354 |
+
#### 9.5.3. エラーハンドリング方針
|
| 355 |
+
- `Summarizer`クラス内で発生したエラー(モデルのロード失敗、推論失敗など)は、クラス内部で適切に捕捉され、呼び出し元がハンドリングしやすいように、専用の例外(例: `InferenceError`)として再送出する設計とします。
|
| 356 |
+
|
| 357 |
+
### 9.6. 詳細設計: 設定管理 (`config.py`) (v1)
|
| 358 |
+
|
| 359 |
+
設定値をコードから分離し、安全かつ構造的に管理するため、以下の通り設計します。
|
| 360 |
+
|
| 361 |
+
#### 9.6.1. 設計方針
|
| 362 |
+
- **データクラスの活用:** Python標準の`dataclasses`を用い、関連する設定項目をグループ化した設定クラス(例: `ModelConfig`)を定義します。これにより、型安全性が保証され、コード補完も効くため開発効率が向上します。
|
| 363 |
+
- **不変性の確保:** 作成したデータクラスは `@dataclass(frozen=True)` を指定し、イミュータブル(変更不可能)にします。これにより、アプリケーション実行中に意図せず設定が変更されてしまう危険な状態を防ぎます。
|
| 364 |
+
- **環境変数による設定の上書き:** 将来的な拡張性(例: APIキーの管理)を見据え、設定値は環境変数から取得することを基本とします。開発環境では`.env`ファイルを利用し、本番環境では実行環境(Hugging Face Spacesなど)のSecrets機能で設定を注入する運用を想定します。
|
| 365 |
+
|
| 366 |
+
- **`.env.example` の提供:** 開発者が環境変数を容易に設定できるよう、リポジトリには `.env.example` ファイルを含めます。実際の開発では、このファイルをコピーして `.env` を作成し、値を設定します。
|
| 367 |
+
|
| 368 |
+
```.env.example
|
| 369 |
+
# AI APIのモデル名を指定
|
| 370 |
+
AI_MODEL_NAME="llm-jp/t5-small-japanese-finetuned-sum"
|
| 371 |
+
```
|
| 372 |
+
|
| 373 |
+
- **`docker-compose.yml` での読み込み:** `docker-compose.yml` ファイルで `env_file` を指定することで、コンテナ起動時に `.env` ファイルの内容が環境変数として読み込まれます。
|
| 374 |
+
|
| 375 |
+
```yaml
|
| 376 |
+
services:
|
| 377 |
+
api:
|
| 378 |
+
build: .
|
| 379 |
+
env_file:
|
| 380 |
+
- .env
|
| 381 |
+
```
|
| 382 |
+
|
| 383 |
+
#### 9.6.2. 構造案
|
| 384 |
+
- **`ModelConfig` クラス:**
|
| 385 |
+
- **責務:** 使用するAIモデルに関する情報を一元管理します。
|
| 386 |
+
- **属性案:** `NAME` (モデル名), `REVISION` (バージョン)
|
| 387 |
+
- **`InferenceConfig` クラス:**
|
| 388 |
+
- **責務:** AIの推論(要約生成)時のパラメータを一元管理します。
|
| 389 |
+
- **属性案:** `MIN_LENGTH`, `MAX_LENGTH`, `LENGTH_PENALTY`, `NUM_BEAMS`
|
| 390 |
+
|
| 391 |
+
### 9.7. 詳細設計: Django側ビュー (`summary_views.py`) (v1)
|
| 392 |
+
|
| 393 |
+
Django側でAI APIを呼び出すビューは、責務を明確に分離し、堅牢なエラーハンドリングとロギングを組み込んだクラスとして設計します。
|
| 394 |
+
|
| 395 |
+
#### 9.7.1. 設計方針
|
| 396 |
+
- **クラスベースビュー (CBV) の採用:** Django標準の`django.views.View`を継承したクラスとして実装します。これにより、将来的な機能拡張(例: POSTメソッドの追加)にも柔軟に対応できます。
|
| 397 |
+
- **責務の分離:** 1つのメソッドに全てのロジックを記述するのではなく、「口コミの取得」「バリデーション」「API呼び出し」といった関心事ごとにプライベートメソッド(例: `_call_api`)へ処理を分割し、メインの`get`メソッドの見通しを良くします。
|
| 398 |
+
- **集中的なエラーハンドリング:** メインの`get`メソッドに`try...except`ブロックを設け、各処理で発生しうる例外(DB関連、通信関連など)を集中的に捕捉し、適切な`JsonResponse`を返すようにします。
|
| 399 |
+
- **詳細なロギング:** Pythonの`logging`モジュールを活用し、API呼び出しの成否、発生したエラー、ビジネスロジックの判断などをログに出力します。特にエラー発生時には、スタックトレースを含めて記録することで、迅速な原因究明を可能にします。
|
| 400 |
+
|
| 401 |
+
#### 9.7.2. クラス・メソッド構成案
|
| 402 |
+
- **`SummarizeReviewsView(View)`**
|
| 403 |
+
- **`get(self, request, playground_id)`:**
|
| 404 |
+
- HTTP GETリクエストを処理するメインメソッド。
|
| 405 |
+
- 以下の処理フローを制御する。
|
| 406 |
+
1. `_get_reviews`を呼び出し、口コミデータを取得。
|
| 407 |
+
2. `_validate_reviews`を呼び出し、ビジネスルール(件数、文字数)を検証。
|
| 408 |
+
3. 口コミテキストを前処理(結合、ノイズ除去)。
|
| 409 |
+
4. `_call_summary_api`を呼び出し、外部APIと通信。
|
| 410 |
+
5. 成功レスポンスまたはエラーレスポンスを`JsonResponse`として返す。
|
| 411 |
+
- **`_get_reviews(self, playground_id)`:**
|
| 412 |
+
- `playground_id`に対応する口コミをデータベースから取得する責務を持つ。
|
| 413 |
+
- **`_validate_reviews(self, reviews)`:**
|
| 414 |
+
- 取得した口コミが要約実行の条件を満たすか検証する責務を持つ。
|
| 415 |
+
- **`_call_summary_api(self, text)`:**
|
| 416 |
+
- `requests`ライブラリを使い、Gradio APIとの通信を行う責務を持つ。タイムアウト設定もここで行う。
|
| 417 |
+
|
| 418 |
+
#### 9.7.3. 設定値の管理
|
| 419 |
+
- Gradio APIのエンドポイントURLやタイムアウト秒数といった設定値は、`settings.py`に記述し、ビューからは`django.conf.settings`を通じて参照します。これにより、設定の一元管理を実現します。
|
| 420 |
+
|
| 421 |
+
### 9.8. 詳細設計: テスト戦略の具体化 (v1)
|
| 422 |
+
|
| 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 |
+
|
| 441 |
+
#### 9.8.3. テストの効率化
|
| 442 |
+
- **フィクスチャの活用 (`@pytest.fixture`):** AIモデルのロードは時間がかかるため、`Summarizer`クラスのインスタンス生成をフィクスチャとして定義します。`scope="session"`を指定することで、全テスト実行中にモデルのロードが一度だけで済み、テスト時間を大幅に短縮します。
|
| 443 |
+
- **パラメータ化の活用 (`@pytest.mark.parametrize`):** 複数の異なる入力値と期待される結果の組み合わせを、一つのテスト関数で効率的に検証するために使用します。
|
| 444 |
+
|
| 445 |
+
### 9.9. 詳細設計: Django-AI連携 (v1)
|
| 446 |
+
|
| 447 |
+
DjangoアプリケーションとAIアプリケーション(Gradio)がどのように連携して機能を実現するかの具体的な設計を以下に示します。
|
| 448 |
+
|
| 449 |
+
#### 9.9.1. 連携シーケンス
|
| 450 |
+
|
| 451 |
+
##### 正常系のシーケンス
|
| 452 |
+
|
| 453 |
+
全体の処理の流れは以下の通りです。
|
| 454 |
+
|
| 455 |
+
```mermaid
|
| 456 |
+
sequenceDiagram
|
| 457 |
+
participant Browser as ユーザー(ブラウザ)
|
| 458 |
+
participant Django as Djangoサーバー
|
| 459 |
+
participant Gradio as AI API (Gradio)
|
| 460 |
+
|
| 461 |
+
Browser->>+Django: GET /summarize/playground/{id}/
|
| 462 |
+
Django->>Django: 1. 口コミ取得・検証
|
| 463 |
+
alt 口コミが3件未満など条件を満たさない
|
| 464 |
+
Django-->>-Browser: JSON (エラー)
|
| 465 |
+
end
|
| 466 |
+
Django->>+Gradio: POST /api/predict/ (口コミテキスト)
|
| 467 |
+
Gradio->>Gradio: 2. AIモデルで要約実行
|
| 468 |
+
Gradio-->>-Django: JSON (要約結果)
|
| 469 |
+
Django-->>-Browser: JSON (要約結果)
|
| 470 |
+
```
|
| 471 |
+
|
| 472 |
+
##### 異常系(AI APIエラー)のシーケンス
|
| 473 |
+
|
| 474 |
+
AI API側でエラーが発生した場合の処理の流れです。
|
| 475 |
+
|
| 476 |
+
```mermaid
|
| 477 |
+
sequenceDiagram
|
| 478 |
+
participant Browser as ユーザー(ブラウザ)
|
| 479 |
+
participant Django as Djangoサーバー
|
| 480 |
+
participant Gradio as AI API (Gradio)
|
| 481 |
+
|
| 482 |
+
Browser->>+Django: GET /summarize/playground/{id}/
|
| 483 |
+
Django->>+Gradio: POST /api/predict/ (口コミテキスト)
|
| 484 |
+
Gradio->>Gradio: AIモデルの処理でエラー発生
|
| 485 |
+
Gradio-->>-Django: HTTP 500 (エラー情報)
|
| 486 |
+
Django->>Django: エラーをログに記録
|
| 487 |
+
Django-->>-Browser: JSON (ユーザー向けエラーメッセージ)
|
| 488 |
+
```
|
| 489 |
+
|
| 490 |
+
#### 9.9.2. 各コンポーネントの責務と実装
|
| 491 |
+
|
| 492 |
+
**1. Django側 (`myapp/views/summary_views.py`)**
|
| 493 |
+
|
| 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`で捕捉し、適切に処理する。
|
| 507 |
+
- 成功時はレスポンスのJSONをパースし、要約テキストを返す。
|
| 508 |
+
|
| 509 |
+
**2. AIアプリケーシ���ン側 (`src/ai_api/`)**
|
| 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/` というエンドポイントを自動的に作成する。
|
| 517 |
+
- **ファイル:** `core/inference.py`
|
| 518 |
+
- **クラス:** `Summarizer`
|
| 519 |
+
- **メソッド:** `summarize(self, text)`
|
| 520 |
+
- **責務:** AIモデルの管理と、実際の要約処理というコアロジックに責任を持つ。
|
| 521 |
+
- **実装詳細:** `transformers`ライブラリを使い、テキストのトークナイズ、モデルによる推論、結果のデコードを行う。
|
| 522 |
+
|
| 523 |
+
#### 9.9.3. 疎結合の担保(独立した開発・テスト)
|
| 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 |
+
|
| 540 |
+
この設計により、両アプリケーションは互いに依存することなく、独立して開発,テスト,デプロイを進めることが可能になります。
|
| 541 |
+
|
| 542 |
+
### 9.10. pyproject.toml の詳細設計
|
| 543 |
+
|
| 544 |
+
ここでのゴールは、プロジェクトで利用する品質管理ツール(Ruff, Mypy, Pytest)の具体的な動作ルールを`pyproject.toml`ファイルに定義し、誰が開発しても、またCI/CDで実行されても、常に一貫した基準でコードの品質がチェックされるようにすることです。
|
| 545 |
+
|
| 546 |
+
#### 1. Ruff (リンター & フォーマッター)
|
| 547 |
+
|
| 548 |
+
高速なリンター兼フォーマッターであるRuffの設定を定義します。
|
| 549 |
+
|
| 550 |
+
##### 設計方針
|
| 551 |
+
- Pythonの標準的なフォーマッターである`black`の規約に準拠させます。
|
| 552 |
+
- 必須のルールに加え、潜在的なバグを発見するルールや、コードをよりモダンな記法に自動修正するルールを積極的に有効化し、コード品質を高く保ちます。
|
| 553 |
+
|
| 554 |
+
##### 設定案 (`[tool.ruff]`セクション)
|
| 555 |
+
- `line-length = 88`: 1行の最大長を`black`に合わせて88文字に設定。
|
| 556 |
+
- `select = ["E", "W", "F", "I", "B", "UP"]`:
|
| 557 |
+
- `E`, `W`, `F`: `pycodestyle`と`Pyflakes`の基本的なエラー・警告(必須)。
|
| 558 |
+
- `I`: `isort`互換のimport文の自動ソート(必須)。
|
| 559 |
+
- `B`: `flake8-bugbear`の、バグの温床となりやすいコードパターンを検出するルール。
|
| 560 |
+
- `UP`: `pyupgrade`の、古いPython記法を新しい記法へ自動的にアップグレードするルール。
|
| 561 |
+
- `target-version = "py312"`: Python 3.12の文法を正しく解釈するように指定。
|
| 562 |
+
|
| 563 |
+
##### 設定案 (`[tool.ruff.format]`セクション)
|
| 564 |
+
- `quote-style = "double"`: コード内での引用符をダブルクォート(`"`)に統一。
|
| 565 |
+
|
| 566 |
+
#### 2. Mypy (静的型チェッカー)
|
| 567 |
+
|
| 568 |
+
型ヒントの正しさを保証するMypyの設定を、厳格かつ実用的に定義します。
|
| 569 |
+
|
| 570 |
+
##### 設計方針
|
| 571 |
+
- 型ヒントの記述をプロジェクト内で徹底させ、型の安全性を高めます。
|
| 572 |
+
- 一方で、型情報を持たない外部ライブラリに起因するエラーは無視し、実用性を損なわないようにします。
|
| 573 |
+
|
| 574 |
+
##### 設定案 (`[tool.mypy]`セクション)
|
| 575 |
+
- `python_version = "3.12"`: 型チェックの対象となるPythonバージョンを指定。
|
| 576 |
+
- `ignore_missing_imports = true`: 型情報(スタブ)が提供されていないライブラリをインポートした際のエラーを無視します。これは多くのプロジェクトで必須の設定です。
|
| 577 |
+
- `disallow_untyped_defs = true`: 型ヒントが書かれていない関数定義をエラーとします。これにより、プロジェクト全体で型ヒントの記述を強制し、コードの可読性と信頼性を飛躍的に向上させます。
|
| 578 |
+
- `warn_return_any = true`: 関数の返り値の型が、曖昧な`Any`型になっている場合に警告を出します。より具体的な型定義を促し、バグを未然に防ぎます。
|
| 579 |
+
|
| 580 |
+
#### 3. Pytest (テストフレームワーク)
|
| 581 |
+
|
| 582 |
+
テストの実行方法に関する設定を定義します。
|
| 583 |
+
|
| 584 |
+
##### 設計方針
|
| 585 |
+
- テストの実行に関する基本的なルールを定め、誰が実行しても同じ結果が得られるようにします。
|
| 586 |
+
|
| 587 |
+
##### 設定案 (`[tool.pytest.ini_options]`セクション)
|
| 588 |
+
- `testpaths = ["tests"]`: テストファイルが格納されているディレクトリを`tests`に限定します。
|
| 589 |
+
- `addopts = "-ra --strict-markers"`: テスト実行時に、詳細なサマリーを表示し(`-ra`)、未定義のテストマーカーの使用を禁止する(`--strict-markers`)ことで、テストの管理を厳格にします。
|
| 590 |
+
- `minversion = "7.0"`: プロジェクトが要求するPytestの最低バージョンを7.0と定め、古いバージョンでの意図しない動作を防ぎます。
|
| 591 |
+
|
| 592 |
+
## 10. さらなる検討事項 (Further Considerations)
|
| 593 |
+
|
| 594 |
+
このセクションでは、v1開発のスコープ外としつつも、本機能の品質と価値を継続的に向上させるために、将来的に調査・実装すべき項目を計画としてまとめる。
|
| 595 |
+
|
| 596 |
+
### 10.1. AIモデルの評価と改善サイクル (MLOps)
|
| 597 |
+
|
| 598 |
+
**目的:** 感覚的な判断を排し、データに基づいてAIの品質を客観的に評価・改善する仕組みを構築する。
|
| 599 |
+
|
| 600 |
+
| 項目 | 調査計画 | 成果物 |
|
| 601 |
+
| : | : | : |
|
| 602 |
+
| **1. 客観的評価指標の導入** | - 要約タスクで一般的に利用される評価指標(ROUGE, BERTScoreなど)を調査する。<br>- Pythonの`evaluate`ライブラリ等を使い、サンプルデータで実際にスコアを算出するPoC(概念実証)を行う。<br>- スコアの計算方法と、その結果の解釈について知見をまとめる。 | - 評価指標の選定理由と使い方をまとめたドキュメント。<br>- スコア算出用のサンプルスクリプト。 |
|
| 603 |
+
| **2. プロンプトエンジニアリング** | - 「ポジティブ/ネガティブ分析」「箇条書き」など、複数の指示(プロンプト)形式を考案する。<br>- 同じ入力データに対し、各プロンプトで生成結果がどう変わるかを比較・分析する。<br>- 最も要約の質が向上するプロンプトのテンプレートを決定する。 | - プロンプトの比較実験の結果レポート。<br>- 採用するプロンプトテンプレート。 |
|
| 604 |
+
| **3. モデルのA/Bテスト** | - 異なるモデルやプロンプトの性能を実環境で比較するためのA/Bテスト基盤を検討する。<br>- リクエストに応じて、バックエンドでモデルを動的に切り替える仕組みを設計する。<br>- ユーザーフィードバックやビジネス指標(例: 滞在時間)への影響を計測し、最適なモデルを選定する。 | - A/Bテストの設計書。<br>- モデル切り替えロジックの実装案。 |
|
| 605 |
+
| **4. モデル更新方針の策定** | - 新しい日本語要約モデルが登場した際に、どのタイミングで評価・導入を行うかの基準を設ける。<br>- 「半年に一度、最新モデルを調査する」「特定の評価指標が10%以上改善する場合に更新を検討する」など、具体的なルールを定義する。 | - モデルのライフサイクル管理方針書。 |
|
| 606 |
+
|
| 607 |
+
### 10.2. 堅牢性とスケーラビリティの向上
|
| 608 |
+
|
| 609 |
+
**目的:** 大量アクセスや予期せぬ入力に対しても、安定して高速なレスポンスを返し、コストを最適化する。
|
| 610 |
+
|
| 611 |
+
| 項目 | 調査計画 | 成果物 |
|
| 612 |
+
| : | : | : |
|
| 613 |
+
| **1. 高度な入力分割戦略** | - 長大な口コミ群に対応するため、テキストを意味のある単位(チャンク)で分割し、それぞれを要約してから最終的に統合する「Map-Reduce」的なアプローチを調査・実装する。<br>- LangChainなどのライブラリが提供する要約チェーンの活用を検討する。 | - チャンク要約の実装PoC。<br>- 長文入力に対するエラー率や品質の改善レポート。 |
|
| 614 |
+
| **2. 非同期API呼び出し** | - DjangoからAI APIを呼び出す処理を非同期化し、Webサーバーのワーカースレッドを長時間ブロックするのを防ぐ���<br>- CeleryやDramatiqといった非同期タスクキューを導入し、要約処理をバックグラウンドジョブとして実行するアーキテクチャを設計する。<br>- フロントエンド側は、ポーリングやWebSocketを利用して、ジョブの完了を検知し結果を表示する方式に変更する。 | - 非同期処理アーキテクチャの設計図。<br>- Celery導入のPoCと、応答性能の改善効果測定レポート。 |
|
| 615 |
+
| **3. キャッシュ戦略の導入** | - Djangoのキャッシュフレームワーク(Redis, Memcachedなど)の利用方法を調査する。<br>- 「施設ID」をキーとして要約結果をキャッシュするアーキテクチャを設計する。<br>- キャッシュの有効期間(TTL)をどの程度に設定すべきか、方針を決定する。 | - キャッシュシステムのアーキテクチャ図。<br>- `settings.py`への設定例と、ビューでの利用コード例。 |
|
| 616 |
+
| **4. コスト・パフォーマンス試算** | - Hugging Face Spacesの無料枠・有料プラン(ハードウェア性能)と料金体系を調査する。<br>- 1リクエストあたりの平均処理時間とメモリ使用量を計測し、無料枠の範囲内で何リクエストまで処理可能か試算する。<br>- 想定されるアクセス数に基づき、月間の運用コストと、スケールアップが必要になる条件を定義する。 | - コストとパフォーマンスの試算レポート。<br>- スケールアップ計画。 |
|
| 617 |
+
|
| 618 |
+
### 10.3. 運用と監視
|
| 619 |
+
|
| 620 |
+
**目的:** 本番環境におけるAPIの稼働状況を可視化し、問題発生時に迅速な検知と対応を可能にする。
|
| 621 |
+
|
| 622 |
+
| 項目 | 調査計画 | 成果物 |
|
| 623 |
+
| : | : | : |
|
| 624 |
+
| **1. ログの統合管理** | - DjangoとGradio APIの両方で、リクエストIDを共有する仕組みを導入する。<br>- 構造化ログ(JSON形式)にリクエストIDを含めることで、Datadogなどの外部サービスで、ユーザーリクエストからAI API呼び出しまでの一連のログを横断的に追跡できるようにする。 | - ログフォーマットの統一仕様。<br>- 構造化ロギングの実装例。 |
|
| 625 |
+
| **2. パフォーマンス監視とエラーレポート** | - Hugging Face Spacesが標準で提供する分析機能(Analytics)で取得できるメトリクスを確認する。<br>- Sentryなどのエラーレポートツールを導入し、アプリケーション例外を自動で収集・通知する仕組みを構築する。<br>- 特に監視すべき重要指標(KPI)を定義する(例: エラー率、95パーセンタイル応答時間、要約品質スコア)。 | - 監視ツールの選定と比較。<br>- 監視KPIリストとその閾値の定義。<br>- Sentry導入手順書。 |
|
| 626 |
+
|
| 627 |
+
### 10.4. ユーザー体験の強化
|
| 628 |
+
|
| 629 |
+
**目的:** AIの機能をよりユーザーフレンドリーで、多くの人が利用しやすい形で提供する。
|
| 630 |
+
|
| 631 |
+
| 項目 | 調査計画 | 成果物 |
|
| 632 |
+
| : | : | : |
|
| 633 |
+
| **1. ユーザーフィードバック機構** | - 要約結果に「役に立ったか (👍/👎)」を投票できるUIを設計する。<br>- フィードバック結果をDjangoのDBに保存するためのデータモデルを設計する。<br>- 収集したデータを将来のモデル再学習やプロンプト改善にどう活かすか、方針を検討する。 | - UIデザイン案。<br>- `models.py`に追加するフィードバックモデルの定義。<br>- データ活用方針の概要。 |
|
| 634 |
+
| **2. 再要約機能** | - ユーザーが生成された要約に満足しなかった場合に、異なるパラメータ(例: より短く、より詳しく)で再生成を試せるUIを設計する。<br>- 「要約のトーンを変える(例: 保護者向け、子供向け)」といった付加機能の実現可能性を調査する。 | - 再要約機能のUIデザイン案。<br>- パラメータ変更機能の実装方針。 |
|
| 635 |
+
| **3. アクセシビリティ (a11y) 対応** | - モーダル表示やボタン操作が、スクリーンリーダー(視覚障害者向け読み上げソフト)で正しく認識・操作できるか検証する。<br>- WCAG (Web Content Accessibility Guidelines) の主要な項目に基づき、キーボードのみでの操作が可能か、十分なコントラスト比が確保されているかなどを確認する。 | - アクセシビリティのチェックリスト。<br>- 対応が必要な箇所の修正案。 |
|
| 636 |
+
|
| 637 |
+
## 11. 実装タスクリスト(詳細版)
|
| 638 |
+
|
| 639 |
+
このセクションでは、TDD(テスト駆動開発)のサイクルに基づき、実装の詳細な手順を階層的に定義します。
|
| 640 |
+
|
| 641 |
+
- **担当: AI** - このアイコンが付いているタスクは、AI(Gemini)がコード生成やファイル作成を直接実行できます。
|
| 642 |
+
- **担当: 人間** - このアイコンが付いているタスクは、開発者による手動での実行、判断、または承認が必要です。
|
| 643 |
+
|
| 644 |
+
### フェーズ0: プロジェクトの初期化
|
| 645 |
+
|
| 646 |
+
**目的:** 新しいプロジェクトの作業を開始するための準備を行う。
|
| 647 |
+
|
| 648 |
+
- [x] **中タスク0.1: プロジェクトルートディレクトリの作成**
|
| 649 |
+
- **担当:** 人間
|
| 650 |
+
- **内容:** 作業を開始するディレクトリに、プロジェクトのルートとなる `kids-playground-ai-api` ディレクトリを作成し、その中に移動してください。
|
| 651 |
+
- **指示:** 以下のコマンドを実行してください。
|
| 652 |
+
```bash
|
| 653 |
+
mkdir kids-playground-ai-api
|
| 654 |
+
cd kids-playground-ai-api
|
| 655 |
+
```
|
| 656 |
+
|
| 657 |
+
### フェーズ1: 開発環境のセットアップ
|
| 658 |
+
|
| 659 |
+
**目的:** コーディングを開始する前に、品質を担保し、開発を効率化するための基盤を構築する。
|
| 660 |
+
|
| 661 |
+
- [x] **中タスク1.0: ドキュメントの配置**
|
| 662 |
+
- **担当:** AI
|
| 663 |
+
- **内容:** この開発ガイド (`ai_api_development_guide.md`) を `docs/` ディレクトリに配置します。
|
| 664 |
+
- **指示:** 以下のコマンドを実行してください。
|
| 665 |
+
```bash
|
| 666 |
+
cp /path/to/current/ai_api_development_guide.md docs/ai_api_development_guide.md
|
| 667 |
+
```
|
| 668 |
+
* *注: `/path/to/current/ai_api_development_guide.md` は、このドキュメントが現在置かれている絶対パスに置き換える必要があります。*
|
| 669 |
+
|
| 670 |
+
- [ ] **中タスク1.1: プロジェクト構造の初期セットアップ**
|
| 671 |
+
- **担当:** AI
|
| 672 |
+
- **内容:** 以下のディレクトリとファイルをプロジェクトルートに作成します。
|
| 673 |
+
- ディレクトリ: `src/ai_api/core`, `tests/core`, `docs`, `.github/workflows`
|
| 674 |
+
- ファイル: `.gitignore`, `Dockerfile`, `pyproject.toml`, `requirements.txt`, `README.md`, `.github/workflows/ci.yml` (空ファイルとして)
|
| 675 |
+
- **指示:** 以下のコマンドを実行して、プロジェクトの初期ディレクトリとファイルを準備してください。
|
| 676 |
+
```bash
|
| 677 |
+
mkdir -p src/ai_api/core tests/core docs .github/workflows
|
| 678 |
+
touch .gitignore Dockerfile pyproject.toml requirements.txt README.md .github/workflows/ci.yml
|
| 679 |
+
```
|
| 680 |
+
|
| 681 |
+
- [ ] **中タスク1.2: 品質管理ツールの設定**
|
| 682 |
+
- [ ] **小タスク1.2.1: `pyproject.toml` の設定**
|
| 683 |
+
- **担当:** AI
|
| 684 |
+
- **内容:** セクション `9.10` の設計に基づき、Ruff, Mypy, Pytestの設定を記述した `pyproject.toml` ファイルを更新します。
|
| 685 |
+
- **指示:** 以下の内容で `/home/jam/kidsPlayGround/pyproject.toml` を更新してください。
|
| 686 |
+
```toml
|
| 687 |
+
# ... (pyproject.toml の内容をここに記述) ...
|
| 688 |
+
```
|
| 689 |
+
|
| 690 |
+
- [ ] **中タスク1.3: 依存関係の管理**
|
| 691 |
+
- [ ] **小タスク1.3.1: `requirements.txt` の設定**
|
| 692 |
+
- **担当:** AI
|
| 693 |
+
- **内容:** 以下のライブラリを記述した `requirements.txt` を更新します。
|
| 694 |
+
- **指示:** 以下の内容で `/home/jam/kidsPlayGround/requirements.txt` を更新してください。
|
| 695 |
+
```
|
| 696 |
+
# AI App
|
| 697 |
+
gradio
|
| 698 |
+
transformers
|
| 699 |
+
torch
|
| 700 |
+
|
| 701 |
+
# Testing
|
| 702 |
+
pytest
|
| 703 |
+
requests
|
| 704 |
+
|
| 705 |
+
# Linting & Formatting
|
| 706 |
+
ruff
|
| 707 |
+
mypy
|
| 708 |
+
```
|
| 709 |
+
- [ ] **小タスク1.3.2: 仮想環境の構築とインストール**
|
| 710 |
+
- **担当:** 人間
|
| 711 |
+
- **内容:** `python -m venv venv`, `source venv/bin/activate`, `pip install -r requirements.txt` を実行し、開発環境を準備します。
|
| 712 |
+
|
| 713 |
+
### フェーズ2: AIアプリケーションのTDD (コアロジック → API)
|
| 714 |
+
|
| 715 |
+
**目的:** クリーンアーキテクチャの原則に従い、内側のビジネスロジックから外側のAPIへと実装を進める。
|
| 716 |
+
|
| 717 |
+
- [ ] **中タスク2.1: AIコアロジック `Summarizer` の実装**
|
| 718 |
+
- [ ] **小タスク2.1.1 (RED):** `Summarizer`クラスのテスト作成
|
| 719 |
+
- **担当:** AI
|
| 720 |
+
- **内容:** `tests/core/test_inference.py` を作成し、「`from src.ai_api.core.inference import Summarizer` が成功すること」をテストします。このテストは、ファイルやクラスが存在しないため失敗します。
|
| 721 |
+
- [ ] **小タスク2.1.2 (GREEN):** `Summarizer`クラスの骨格作成
|
| 722 |
+
- **担当:** AI
|
| 723 |
+
- **内容:** `src/ai_api/core/inference.py` と、空の`Summarizer`クラスを作成し、テストをパスさせます。
|
| 724 |
+
- [ ] **小タスク2.1.3 (REFACTOR):** リファクタリング
|
| 725 |
+
- **担当:** AI
|
| 726 |
+
- **内容:** この時点では特になし。コミットの区切りとします。
|
| 727 |
+
|
| 728 |
+
- [ ] **中タスク2.2: AI設定クラス `Config` の実装と注入**
|
| 729 |
+
- [ ] **小タスク2.2.1 (RED):** `Summarizer`が設定オブジェクトを受け取るテスト作成
|
| 730 |
+
- **担当:** AI
|
| 731 |
+
- **内容:** `tests/core/test_inference.py`に追記します。
|
| 732 |
+
- **内容:** `Summarizer`がコンストラクタで設定オブジェクト(モデル名など)を受け取ることを期待するテストを`tests/core/test_inference.py`に追記します。
|
| 733 |
+
- [ ] **小タスク2.2.2 (GREEN):** 設定クラスの作成とコンストラクタ修正
|
| 734 |
+
- **担当:** AI
|
| 735 |
+
- **内容:** `src/ai_api/config.py`に設計通りの設定クラス(`ModelConfig`など)を作成します。`Summarizer`の`__init__`を修正し、設定オブジェクトを受け取るようにします。
|
| 736 |
+
- [ ] **小タスク2.2.3 (REFACTOR):** リファクタリング
|
| 737 |
+
- **担当:** AI
|
| 738 |
+
- **内容:** コードの可読性を向上させます。 **この時点で、AIモデルを切り替えるための基本的な仕組み(設定値を外部から与える)が完成します。**
|
| 739 |
+
|
| 740 |
+
- [ ] **中タスク2.3: 要約機能 `summarize` メソッドの実装**
|
| 741 |
+
- [ ] **小タスク2.3.1 (RED):** `summarize`メソッドのユニットテスト作成
|
| 742 |
+
- **担当:** AI
|
| 743 |
+
- **内容:** `unittest.mock.patch`を使い、`transformers.pipeline`をモック(偽物に差し替え)します。「`summarize`メソッドを呼ぶと、内部で`pipeline`が特定の引数で呼ばれ、モックの返り値がそのまま返されること」をテストします。これにより、重いモデルをロードせずにロジックだけを高速にテストできます。
|
| 744 |
+
- [ ] **小タスク2.3.2 (GREEN):** `summarize`メソッドの実装
|
| 745 |
+
- **担当:** AI
|
| 746 |
+
- **内容:** `Summarizer`クラスに`summarize`メソッドを実装し、内部で`transformers.pipeline`を呼び出して要約を実行するようにします。
|
| 747 |
+
- [ ] **小タスク2.3.3 (REFACTOR):** リファクタリング
|
| 748 |
+
- **担当:** AI
|
| 749 |
+
- **内容:** エラーハンドリングなどを追加し、コードを整理します。
|
| 750 |
+
|
| 751 |
+
- [ ] **中タスク2.4: APIエントリーポイント `main.py` の実装**
|
| 752 |
+
- [ ] **小タスク2.4.1 (RED):** APIのインテグレーションテスト作成
|
| 753 |
+
- **担当:** AI
|
| 754 |
+
- **内容:** `tests/test_api.py`を作成します。テスト内でGradioアプリを別スレッドで起動し、`requests.post`で`/api/predict/`にリクエストを送信して、期待した応答が得られない(サーバーがないため)ことを確認します。
|
| 755 |
+
- [ ] **小タスク2.4.2 (GREEN):** `main.py`の実装
|
| 756 |
+
- **担当:** AI
|
| 757 |
+
- **内容:** `src/ai_api/main.py`を作成します。`Summarizer`と設定クラスをインスタンス化し、DI(依存性の注入)してGradioの`Interface`を定義・起動します。
|
| 758 |
+
- [ ] **小タスク2.4.3 (REFACTOR):** リファクタリング
|
| 759 |
+
- **担当:** AI
|
| 760 |
+
- **内容:** コードを整理します。
|
| 761 |
+
- [ ] **小タスク2.4.4: 手動での動作確認**
|
| 762 |
+
- **担当:** 人間
|
| 763 |
+
- **内容:** `python src/ai_api/main.py` を実行し、ブラウザで表示されるGradioのUIにテキストを入力して、要約機能が単体で正しく動作することを確認します。
|
| 764 |
+
|
| 765 |
+
### フェーズ3: Djangoへの組み込み
|
| 766 |
+
|
| 767 |
+
**目的:** 独立して動作するAIアプリケーションを、DjangoからAPI経由で安全に呼び出す。
|
| 768 |
+
|
| 769 |
+
- [ ] **中タスク3.1: Django側のAPIクライアント実装**
|
| 770 |
+
- [ ] **小タスク3.1.1 (RED):** APIクライアントのテスト作成
|
| 771 |
+
- **担当:** AI
|
| 772 |
+
- **内容:** `myapp/tests/test_clients.py`を作成します。`requests.post`がモック化されている状態でAPIクライアント関数を呼び出し、成功時・タイムアウト時・サーバーエラー時の挙動をテストします。
|
| 773 |
+
- [ ] **小タスク3.1.2 (GREEN):** APIクライアントの実装
|
| 774 |
+
- **担当:** AI
|
| 775 |
+
- **内容:** `myapp/clients/ai_summary_client.py`を作成し、`requests`を使って外部APIを呼び出す関数を実装します。
|
| 776 |
+
- [ ] **小タスク3.1.3 (REFACTOR):** リファクタリング
|
| 777 |
+
- **担当:** AI
|
| 778 |
+
- **内容:** 設定を`settings.py`から読み込むようにするなど、コードを整理します。
|
| 779 |
+
|
| 780 |
+
- [ ] **中タスク3.2: Django Viewの実装**
|
| 781 |
+
- [ ] **小タスク3.2.1 (RED):** ViewのURLテスト作成
|
| 782 |
+
- **担当:** AI
|
| 783 |
+
- **内容:** `myapp/tests/test_views.py`に、`/summarize/playground/{id}/`へのGETリクエストが404を返すテストを書きます。
|
| 784 |
+
- [ ] **小タスク3.2.2 (GREEN):** URLとViewの骨格作成
|
| 785 |
+
- **担当:** AI
|
| 786 |
+
- **内容:** `myapp/urls.py`と`myapp/views/summary_views.py`を作成・編集し、テストをパスさせます。
|
| 787 |
+
- [ ] **小タスク3.2.3 (RED):** Viewとクライアントの連携テスト作成
|
| 788 |
+
- **担当:** AI
|
| 789 |
+
- **内容:** `unittest.mock.patch`でAPIクライアントをモック化し、「Viewを呼び出すと、内部でAPIクライアントが特定の引数で呼ばれること」をテストします。
|
| 790 |
+
- [ ] **小タスク3.2.4 (GREEN):** Viewロジックの実装
|
| 791 |
+
- **担当:** AI
|
| 792 |
+
- **内容:** View内で口コミの取得・検証ロジック、およびAPIクライアントの呼び出しを実装します。
|
| 793 |
+
- [ ] **小タスク3.2.5 (REFACTOR):** リファクタリング
|
| 794 |
+
- **担当:** AI
|
| 795 |
+
- **内容:** コードを整理します。
|
| 796 |
+
|
| 797 |
+
- [ ] **中タスク3.3: 統合テスト**
|
| 798 |
+
- [ ] **小タスク3.3.1: 手動での最終確認**
|
| 799 |
+
- **担当:** 人間
|
| 800 |
+
- **内容:** DjangoサーバーとAIアプリ(Gradio)を両方ローカルで起動し、ブラウザから最初の要約ボタンをクリックして、全体の流れが正しく動作するかを確認します。
|
| 801 |
+
|
| 802 |
+
```
|
pyproject.toml
ADDED
|
File without changes
|
requirements.txt
ADDED
|
File without changes
|