File size: 69,992 Bytes
af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 afe743c af07d37 afe743c af07d37 afe743c af07d37 d270dd6 af07d37 d270dd6 f079f59 d270dd6 af07d37 4cbfa8c f079f59 4cbfa8c af07d37 d270dd6 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 af07d37 f079f59 a41dc78 af07d37 f079f59 af07d37 fda27e7 d270dd6 fda27e7 030a5b9 fda27e7 f079f59 fda27e7 030a5b9 afe743c f079f59 fda27e7 5e60243 fda27e7 af07d37 030a5b9 af07d37 030a5b9 f2b593b af07d37 5e60243 af07d37 f2b593b af07d37 f2b593b af07d37 3bf36b5 af07d37 f2b593b f079f59 f2b593b 5e60243 a41dc78 afe743c d270dd6 a41dc78 d270dd6 a41dc78 d270dd6 a41dc78 d270dd6 afe743c d270dd6 a41dc78 d270dd6 a41dc78 d270dd6 a41dc78 d270dd6 a41dc78 d270dd6 afe743c d270dd6 afe743c d270dd6 afe743c d270dd6 afe743c d270dd6 af07d37 afe743c af07d37 afe743c af07d37 a41dc78 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 afe743c af07d37 9b7b57a af07d37 f079f59 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 |
# AI API éçºã¬ã€ã
ãã®ããã¥ã¡ã³ãã¯ãHugging Face SpacesãšGradioãå©çšããAI APIã®éçºç°å¢æ§ç¯ãšããã®åŸã®éçºããã»ã¹ã«é¢ããèŠç¹ããŸãšãããã®ã§ãã
## 1. æŠèŠ
### 1.1. ç®çãšæ©èœæŠèŠ
æ¬ãããžã§ã¯ãã®ç®çã¯ãã芪åã§éãŒããããã«AIãæŽ»çšãã**å£ã³ãã®èªåèŠçŽæ©èœ**ãå®è£
ããããšã§ãã
- **ç®ç:** ãŠãŒã¶ãŒã倿°ã®å£ã³ããå
šãŠèªãã§ããæœèšã®å
šäœçãªè©å€ãçŽ æ©ãããã€å®¢èгçã«ææ¡ã§ããããã«ããã
- **ãŠãŒã¶ãŒäœéš:**
1. ãŠãŒã¶ãŒã¯æœèšã®è©³çްããŒãžã§ãå£ã³ããAIèŠçŽããã¿ã³ãã¯ãªãã¯ããŸãã
2. AIããã®æœèšã®å
šå£ã³ããåæãããããžãã£ããªç¹ããšã泚æãå¿
èŠãªç¹ããªã©ããŸãšããäžç«çãªèŠçŽæãçæããŸãã
3. çæãããèŠçŽãã¢ãŒãã«ãŠã£ã³ããŠçã§è¡šç€ºããããŠãŒã¶ãŒã¯çæéã§æœèšã®é·æãšçæãçè§£ã§ããŸãã
### 1.2. ã¢ãŒããã¯ãã£æŠèŠ
ãã®æ©èœã¯ãDjangoã¢ããªã±ãŒã·ã§ã³ãšãHugging Face Spacesäžã§åäœããGradio APIãšã®é£æºã«ãã£ãŠå®çŸããŸãã
- **éçºç°å¢:** Dockerã³ã³ããå
ã§éçºã»ãã¹ããè¡ãã
- **ããŒãžã§ã³ç®¡ç:** Gitã§ã³ãŒãã管çããã
- **CI/CD:** GitHub Actionsã§ãã¹ããšãããã€ãèªååããã
- **æ¬çªç°å¢:** Hugging Face Spacesã«ãããã€ããAPIãå
¬éããã
### 1.3. æè¡éžå®çç±
- **Hugging Face Spaces:**
- **éžå®çç±:** ç¡ææ ãå©çšå¯èœã§ãè¿
éãªãããã¿ã€ãã³ã°ã«é©ããŠããŸãããŸããGitHubãªããžããªãšé£æºããèªåãããã€æ©èœïŒCI/CDïŒãæšæºã§æäŸãããŠãããéçºäœéšãéåžžã«ã¹ã ãŒãºã§ãã
- **ä»£æ¿æ¡ãšã®æ¯èŒ:** AWS LambdaãGoogle Cloud Functionsã®ãããªãµãŒããŒã¬ã¹ç°å¢ãèããããŸããããããã¯ã³ã³ããã€ã¡ãŒãžã®ãµã€ãºå¶éãå³ãããå€§èŠæš¡ãªAIã¢ãã«ã®ãããã€ã«ã¯è¿œå ã®å·¥å€«ãå¿
èŠã§ããHugging Face Inference APIã¯æãæè»œã§ãããã«ã¹ã¿ã ããžãã¯ã®è¿œå ãUIã®æäŸãã§ããªããããä»åã¯Gradioãšçµã¿åãããããSpacesãéžæããŸããã
- **Gradio:**
- **éžå®çç±:** æ°è¡ã®ã³ãŒãã§AIã¢ãã«ã®ãã¢UIãšAPIãšã³ããã€ã³ããåæã«äœæã§ãããããéçºé床ã倧å¹
ã«åäžãããŸããç¹ã«ãåäœç¢ºèªçšã®UIãèªåã§çæãããç¹ã¯ãéçºåææ®µéã§ã®å®éšããããã°ã«ãããŠå€§ããªå©ç¹ãšãªããŸãã
### 1.4. ã¢ãŒããã¯ãã£å³
```mermaid
graph TD
subgraph "ãŠãŒã¶ãŒç°å¢"
Browser[ãŠãŒã¶ãŒã®ãã©ãŠã¶]
end
subgraph "WebãµãŒã㌠(Django)"
A[Django View] -- DBããå£ã³ãååŸ --> DB[(PostgreSQL)]
A -- èŠçŽãªã¯ãšã¹ã --> B{API Client}
B -- HTTP POST --> C[AI API Gateway]
end
subgraph "AIæšè«ç°å¢ (Hugging Face Spaces)"
C -- èªèšŒã»ã«ãŒãã£ã³ã° --> D[Gradio App]
D -- æšè«å®è¡ --> E[Summarization Model]
end
Browser -- "1. èŠçŽãã¿ã³ã¯ãªãã¯" --> A
C -- "3. èŠçŽçµæ (JSON)" --> B
A -- "4. èŠçŽçµæ (JSON)" --> Browser
style DB fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#ccf,stroke:#333,stroke-width:2px
```
---
## 2. ãããžã§ã¯ãæ§é ãšéçºç°å¢
ä¿å®æ§ã»æ¡åŒµæ§ãé«ããããã圹å²ããšã«ãã¡ã€ã«ãåå²ãããã£ã¬ã¯ããªæ§é ãæ¡çšããDockerã§éçºç°å¢ãæ§ç¯ããŸãã
### 2.1. æšå¥šãã£ã¬ã¯ããªæ§é
```
kids-playground-ai-api/
â
âââ .github/
â âââ workflows/
â âââ ci.yml
â
âââ .gitignore
âââ Dockerfile
âââ pyproject.toml
âââ requirements.txt
âââ README.md
â
âââ docs/
â âââ ai_api_development_guide.md # â
ãã®éçºã¬ã€ã
â
âââ src/
â âââ ai_api/
â âââ __init__.py
â âââ main.py # APIãšã³ããªãŒãã€ã³ã (Gradio UI)
â âââ core/
â â âââ __init__.py
â â âââ inference.py # AIæšè«ããžãã¯
â âââ config.py # èšå®ãã¡ã€ã«
â
âââ tests/
âââ core/
âââ test_inference.py
```
### 2.2. å質管çããŒã«ã®èšå®
- **`pyproject.toml`:** ãããžã§ã¯ãã«ãŒãã«äœæããRuff (ãã©ãŒããã¿ãŒ/ãªã³ã¿ãŒ), Mypy (åãã§ãã«ãŒ), Pytest (ãã¹ããã¬ãŒã ã¯ãŒã¯) ã®èšå®ãèšè¿°ããŸãã
- **`.pre-commit-config.yaml`:** `pre-commit`ãå°å
¥ããGitã³ãããæã«èªåã§ã³ãŒããã§ãã¯ãèµ°ãããã«èšå®ããŸãã
### 2.3. éçºç°å¢ (Docker)
- **`requirements.txt`:** å¿
èŠãªã©ã€ãã©ãªãèšè¿°ããŸãã
- **`Dockerfile`:** ããŒã«ã«éçºç°å¢ã®çµ±äžãšå¹çåã®ããã«äœ¿çšããŸãã
- **泚èš:** ãã®`Dockerfile`ã¯ããããŸã§ããŒã«ã«éçºçšã§ãããããã€å
ã®Hugging Face Spacesã§ã¯ã`Dockerfile`ã¯çŽæ¥äœ¿ãããã`requirements.txt`ã«åºã¥ããŠç°å¢ãèªåæ§ç¯ãããŸãã
- **`docker-compose.yml`:** DjangoãµãŒããŒãšAI APIãµãŒããŒãªã©ãè€æ°ã®ãµãŒãã¹ãå®çŸ©ããäžæ¬ã§èµ·åã»ç®¡çããããã«äœ¿çšããŸãã
- **Docker Desktopã®æŽ»çš:** WindowsãMacã®ãŠãŒã¶ãŒã¯ãDocker Desktopãå©çšããããšã§ãã³ã³ããã®ç¶æ
ãGUIã§èŠèŠçã«ç¢ºèªããããèµ·åã»åæ¢ã容æã«è¡ãããšãã§ããŸããLinuxãŠãŒã¶ãŒãå©çšå¯èœã§ããã³ãã³ãã©ã€ã³æäœã«æ
£ããŠããªãéçºè
ã«ã¯ãDocker Desktopã®å©çšãæšå¥šããŸãã
#### 2.3.1. ããŒã«ã«ç°å¢ã®èµ·åãšã¢ã¯ã»ã¹
éçºãéå§ããã«ã¯ããããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã§ä»¥äžã®ã³ãã³ããå®è¡ããŸããDocker Desktopãå©çšããŠããå Žåã¯ãGUIäžãã `docker-compose.yml` ãæå®ããŠèµ·åããããšãå¯èœã§ãã
```bash
# -d ãã©ã°ã§ããã¯ã°ã©ãŠã³ãã§èµ·å
docker-compose up --build -d
```
ããã«ãããåãµãŒãã¹ãã³ã³ãããšããŠèµ·åããŸãã
- **Djangoã¢ããªã±ãŒã·ã§ã³:** `http://localhost:8000`
- **AI API (Gradio):** `http://localhost:7860`
### 2.4. ãããã°æ¹æ³
ã³ã³ããå
ã§åé¡ãçºçããå Žåã以äžã®ã³ãã³ãã§ã³ã³ããã®å
éšã«å
¥ãããããã°äœæ¥ãè¡ãããšãã§ããŸãã
```bash
# <service_name> 㯠docker-compose.yml ã§å®çŸ©ãããµãŒãã¹å (äŸ: web, api)
docker-compose exec <service_name> bash
```
ã³ã³ããå
ã§ã¯ããã°ãã¡ã€ã«ã®ç¢ºèªãPythonã®ã€ã³ã¿ã©ã¯ãã£ãã·ã§ã«ãèµ·åããŠã®ã³ãŒãå®è¡ãªã©ãå¯èœã§ãã
---
## 3. ã¢ãã«ç®¡ç
- **ã¢ãã«éžå®:** ãŸãã¯é床ãšãªãœãŒã¹ã®ãã©ã³ã¹ãè¯ã軜éãªã¢ãã«ïŒäŸ: `llm-jp/t5-small-japanese-finetuned-sum`ïŒã§éçºãéå§ããå¿
èŠã«å¿ããŠãããé«å質ãªã¢ãã«ïŒäŸ: `izumi-lab/t5-base-japanese-summary`ïŒãžã®å·®ãæ¿ããæ€èšããŸãã
- **æ
å ±èšé²:** `config.py`ã«ã¯ãã¢ãã«åã ãã§ãªããã¢ãã«ãµã€ãºãã©ã€ã»ã³ã¹ãæšè«é床ã®ç®å®ãªã©ã®æ
å ±ãã³ã¡ã³ããšããŠèšé²ãã管çããŸãã
---
## 4. å®è£
ã®åœ¹å²åæ
- **`src/ai_api/config.py` (èšå®æ
åœ):** ã¢ãã«ããã©ã¡ãŒã¿ã®æ
å ±ã管çããŸãã
- **`src/ai_api/core/inference.py` (AIæšè«æ
åœ):** AIã¢ãã«ã®ããŒããšæšè«ã®ã³ã¢ããžãã¯ãå®è£
ããŸãã
- **`src/ai_api/main.py` (APIå仿
åœ):** Gradioã®UIãå®çŸ©ãããµãŒããŒãèµ·åããŸããDockerã³ã³ããå
ã§å€éšã«APIãå
¬éããããã`iface.launch(server_name="0.0.0.0")`ã®ããã«èµ·åãªãã·ã§ã³ãæå®ããŸãã
### AIæ°æ©èœéçºã«ãããã³ãŒãã£ã³ã°èŠçŽ
AIæ°æ©èœã®éçºã«ãããŠã¯ã以äžã®ã³ãŒãã£ã³ã°èŠçŽãšéçºååãéµå®ããé«å質ã§ä¿å®æ§ã®é«ãã³ãŒãããŒã¹ãç®æããŸãã
#### 1. Pythonã³ãŒãã£ã³ã°èŠçŽ
* **PEP 8æºæ **: Pythonã³ãŒãã¯PEP 8ã¹ã¿ã€ã«ã¬ã€ãã«å³å¯ã«æºæ ããŸãã`flake8` ããã³ `black` ã«ããèªåãã©ãŒããããšãªã³ãã培åºããã³ãŒãã®äžè²«æ§ãä¿ã¡ãŸãã
* **åãã³ãã®æŽ»çš**: `mypy` ãçšããåãã§ãã¯ã培åºããã³ãŒãã®å
ç¢æ§ãå¯èªæ§ãããã³IDEã«ããè£å®ã®æ©æµãæå€§åããŸãã
* **Djangoãšã®é£æº**: AIæ©èœãDjangoã¢ããªã±ãŒã·ã§ã³ãšé£æºããå ŽåãDjangoã®ã¢ãã«ããã¥ãŒããã©ãŒã ãURLãã¿ãŒã³ãªã©ã®æ¢åã®åœåèŠåãšæ§é ã«æºæ ããã·ãŒã ã¬ã¹ãªçµ±åãå³ããŸãã
* **AI/MLã³ãŒãã®æ§é **:
- ããŒã¿åŠçïŒååŠçãç¹åŸŽéãšã³ãžãã¢ãªã³ã°ïŒãã¢ãã«å®çŸ©ãåŠç¿ããžãã¯ãæšè«ããžãã¯ã¯æç¢ºã«åé¢ãããããããåäžã®è²¬åãæã€ã¢ãžã¥ãŒã«ãšããŠèšèšããŸãã
- èšå®å€ããã€ããŒãã©ã¡ãŒã¿ã¯ã³ãŒãããåé¢ããDjangoã®`settings.py`ããŸãã¯å°çšã®YAML/JSONãã¡ã€ã«ãªã©ã§äžå
çã«ç®¡çããŸãã
* **ããã¥ã¡ã³ããŒã·ã§ã³**: 颿°ãã¯ã©ã¹ãè€éãªã¢ã«ãŽãªãºã ãããã³AIã¢ãã«ã®èšèšæå³ã«ã¯ãé©åãªDocstringãèšè¿°ããã³ãŒãã®æå³ãšæ¯ãèããæç¢ºã«ããŸãã
* **ãšã©ãŒãã³ããªã³ã°**: äºæãã¬ãšã©ãŒãäŸå€åŠçã¯ãDjangoã®æšæºçãªãšã©ãŒãã³ããªã³ã°ãPythonã®äŸå€åŠçã¡ã«ããºã ã«åŸããé©åã«ãã°ãåºåããã·ã¹ãã ã®å®å®æ§ã確ä¿ããŸãã
* **ä¿å®æ§ãšå¯èªæ§**: ã³ãŒãã¯åžžã«ä¿å®æ§ãšå¯èªæ§ãæåªå
ã«èšèšã»å®è£
ããŸããè€éãªããžãã¯ã¯å°ããªé¢æ°ã«åå²ãã倿°åã颿°åã¯æå³ãæç¢ºã«äŒããããã«åœåããŸãã
* **åäžè²¬åã®åå (SRP)**: ã¯ã©ã¹ã颿°ã¯ã倿Žã®çç±ãäžã€ã§ããããã«èšèšããŸããããã«ãããã³ãŒãã®åé床ãé«ãããã¹ãå®¹ææ§ãšåå©çšæ§ãåäžãããŸãã
#### 2. ãã¹ãé§åéçº (TDD) ãšãã¹ãã®èãæ¹
* **t_wadaæ°ã®TDDã¹ã¿ã€ã«**: éçºã¯ãRed â Green â Refactorãã®TDDãµã€ã¯ã«ãå³å®ããŠé²ããŸãã
- **Red**: æåã«å€±æãããã¹ããèšè¿°ããå¿
èŠãªæ©èœã®æ¯ãèããå®çŸ©ããŸãã
- **Green**: ãã¹ããæåããæå°éã®ã³ãŒããå®è£
ããŸãã
- **Refactor**: ã³ãŒãã®å質ãåäžãããéè€ãæé€ããèšèšãæ¹åããŸãã
* **ãåã仿§æžããšããŠã®ãã¹ã**: ãã¹ãã³ãŒãã¯ãåãªãå質ä¿èšŒã®ææ®µã§ã¯ãªããæ©èœã®æ¯ãèããæç¢ºã«èšè¿°ãããåã仿§æžããšããŠæ©èœããããã«èšèšããŸãã
- ãã¹ãã±ãŒã¹åïŒ`pytest`ã®ãã¹ã颿°åãªã©ïŒã¯ã**æ¥æ¬èªã§**ãããšããç¶æ³ã§ãããšããæ¯ãèãããã¹ãããšããããã«ãå
·äœçãªã·ããªãªãšæåŸ
ãããçµæãèšè¿°ããŸãã
- ãã¹ãã¯å®è£
ã®è©³çްã§ã¯ãªããæ©èœã®**æ¯ãèãïŒBehaviorïŒ**ã«çŠç¹ãåœãŠãŸãã
---
## 5. ãã¹ãæŠç¥
- **ãŠããããã¹ã:** `pytest`ã䜿ãã`inference.py`å
ã®çŽç²ãªé¢æ°ïŒAIã®ã³ã¢ããžãã¯ïŒããã¹ãããŸãã
- **ã€ã³ãã°ã¬ãŒã·ã§ã³ãã¹ã:** ããŒã«ã«ã§èµ·åããGradioãµãŒããŒã«å¯Ÿãã`requests`ã©ã€ãã©ãªã§å®éã«APIãªã¯ãšã¹ããéããHTTPã¹ããŒã¿ã¹ã³ãŒããã¬ã¹ãã³ã¹ã®åœ¢åŒãæåŸ
éãã§ããããšã確èªãããã¹ãã远å ããŸããããã«ãããAPIãšããŠã®æ£åžžæ§ãä¿èšŒããŸãã
---
## 6. CI/CDãšãããã€æŠç¥
### 6.1. æšå¥šã¯ãŒã¯ãããŒ
1. **CI (GitHub Actions):** ãã«ãªã¯ãšã¹ãäœææã`main`ãã©ã³ããžã®ããã·ã¥æã«ãGitHub Actionsãèµ·åãã`pytest`ã«ããèªåãã¹ãïŒãŠããããã¹ããšã€ã³ãã°ã¬ãŒã·ã§ã³ãã¹ãïŒãå®è¡ããŸãã
2. **CD (GitHub Actionsã«ãããããã€):** ãã¹ããæåããã³ãŒãã`main`ãã©ã³ãã«ããŒãžãããããGitHub Actionsã®ã¯ãŒã¯ãããŒãHugging Faceã®ã¢ã¯ã»ã¹ããŒã¯ã³ã䜿ã£ãŠãHugging Face Spacesã®ãªããžããªã«çŽæ¥`git push`ããŸããããã«ããããããã€ãèªåçã«å®è¡ãããŸãã
### 6.2. èšå®
- **GitHub Actions:** `.github/workflows/ci.yml`ã«ãã¹ããšãããã€ã®ã¯ãŒã¯ãããŒãå®çŸ©ããŸãã
- **Hugging Face Hub & GitHub Secrets:**
1. Hugging Faceã®å人èšå®ã§ã`write`æš©éãæã€ã¢ã¯ã»ã¹ããŒã¯ã³ãçºè¡ããŸãã
2. çºè¡ããããŒã¯ã³ããGitHubãªããžããªã®`Settings > Secrets and variables > Actions`ã«`HF_TOKEN`ãšããŠç»é²ããŸãã
3. `ci.yml`å
ã®ãããã€ãžã§ãã¯ããã®`HF_TOKEN`ãå®å
šã«å©çšããŠHugging Faceãžã®èªèšŒãè¡ããŸãã
---
## 7. ã»ãã¥ãªãã£ãšå©çšå¶é
### 7.1. APIèªèšŒ
**課é¡:** Hugging Face Spacesã§å
¬éãããAPIã¯ãããã©ã«ãã§ã¯èª°ã§ãã¢ã¯ã»ã¹å¯èœãªç¶æ
ã«ãªããŸããæå³ããªãå©çšãæ»æãé²ããããèªèšŒãå°å
¥ããå¿
èŠããããŸãã
**察ç:** Gradioãæšæºã§æäŸãããã¹ã¯ãŒãèªèšŒæ©èœãå©çšããŸãã
1. **èªèšŒæ
å ±ã®èšå®:**
- `GRADIO_PASSWORD`: APIãä¿è·ããããã®ãã¹ã¯ãŒããç°å¢å€æ°ã§èšå®ããŸãã
2. **Secretsãžã®ç»é²:**
- **APIãµãŒããŒåŽ (Hugging Face):** `GRADIO_PASSWORD`ã®å€ããHugging Face Spacesã®Secretsã«ç»é²ããŸãã
- **ã¯ã©ã€ã¢ã³ãåŽ (Renderãªã©):** åããã¹ã¯ãŒãããã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã®ç°å¢å€æ° `AI_SUMMARY_API_KEY` ãšããŠç»é²ããŸãã
3. **èªèšŒã®å®è£
:**
- **GradioåŽ:** `iface.launch(auth=(username, password))` ã®åœ¢åŒã§èªèšŒãæå¹ã«ããŸãããŠãŒã¶ãŒåã¯çŸåš `gemini` ã§åºå®ãããŠããããã¹ã¯ãŒãã¯ç°å¢å€æ°ããèªã¿èŸŒãŸããŸãã
- **ã¯ã©ã€ã¢ã³ãåŽ:** `gradio_client`ãå©çšããéã`auth=("gemini", api_key)` ã®ããã«èªèšŒæ
å ±ãæž¡ããŠAPIãåŒã³åºããŸãã
### 7.2. ãã®ä»ã®å¯Ÿç
- **Abuse察ç:** å
¬éAPIãæªçšãããã®ãé²ããããGradioã®`queue()`ã¡ãœãããå©çšããŠãªã¯ãšã¹ããåŸ
ã¡è¡åã«å
¥ããåæã¢ã¯ã»ã¹æ°ãå¶éããããšãæ€èšããŸãã
- **å
責äºé
:** `README.md`ã«ãAPIã®å©çšã¯èªå·±è²¬ä»»ã§ããããšãçæãããå
å®¹ã®æ£ç¢ºæ§ãä¿èšŒããªãããšãåçšå©çšã«é¢ããå¶éãªã©ãæèšããŠãããŸãã
---
## 8. ä»åŸã®éçºããã»ã¹
ãã®ããã¥ã¡ã³ãã¯ãä»åŸã®èª¿æ»ãéçºã®é²æã«å¿ããŠãç¶ç¶çã«æŽæ°ã»ã¡ã³ããã³ã¹ãããŸãã
---
## 9. èšèš
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãæ©èœå®è£
ã®åã«å®çŸ©ããã¹ãããã詳现ãªèšèšã«ã€ããŠèšé²ããŸãã
### 9.1. APIã€ã³ã¿ãŒãã§ãŒã¹èšèš (å£ã³ãèŠçŽæ©èœ v1)
DjangoãšGradio APIãããåãããããŒã¿åœ¢åŒãšã«ãŒã«ã以äžã®ããã«å®ããŸãã
#### 9.1.1. åºæ¬æ¹é
- **éä¿¡ãããã³ã«:** HTTP/HTTPS
- **ããŒã¿åœ¢åŒ:** JSON
- **åºæ¬æ§é :** Gradioã®æšæºAPI圢åŒã«æºæ ããŸãã
#### 9.1.2. ãªã¯ãšã¹ã仿§ (Django â Gradio API)
- **ãšã³ããã€ã³ã:** `(Spaceã®URL)/api/predict/`
- **HTTPã¡ãœãã:** `POST`
- **ãã㣠(JSON):**
```json
{
"data": [
"å£ã³ãå
šæãçµåããæåå..."
]
}
```
#### 9.1.3. ã¬ã¹ãã³ã¹ä»æ§ (Gradio API â Django)
**æåæ (HTTP 200 OK):**
- **ãã㣠(JSON):**
```json
{
"data": [
"AIã«ãã£ãŠçæãããèŠçŽæ..."
],
"duration": 3.5
}
```
**å€±ææ (HTTP 500 Internal Server Error):**
- **ãã㣠(JSON):**
```json
{
"error": "GradioåŽã§èšå®ãããšã©ãŒã¡ãã»ãŒãž"
}
```
### 9.2. UI/UXèšèš (å£ã³ãèŠçŽæ©èœ v1)
ãŠãŒã¶ãŒãæ©èœãçŽæçã«å©çšã§ããã·ã¹ãã ã®å¿çãå¿«é©ã«åŸ
ãŠãããã«ã以äžã®éãUI/UXãèšèšããŸãã
#### 9.2.1. æäœãããŒ
1. **ããªã¬ãŒ:** ãŠãŒã¶ãŒãæœèšè©³çްããŒãžã®ãå£ã³ããAIèŠçŽããã¿ã³ãã¯ãªãã¯ããŸãã
2. **ããŒãã£ã³ã°:** ãã¿ã³ãç¡å¹åããããçæäžã§ã...ããšããããã¹ããšã¹ãããŒïŒå転ããã¢ã€ã³ã³ïŒã衚瀺ãããŸããããã«ãããåŠçäžã§ããããšããŠãŒã¶ãŒã«æç¢ºã«äŒãããŸãã
3. **çµæè¡šç€º:** èŠçŽãå®äºãããšã**Bootstrapã®ã¢ãŒãã«ãŠã£ã³ããŠ**ãç»é¢äžå€®ã«è¡šç€ºããããã®äžã«çæãããèŠçŽæãæç€ºãããŸãã
4. **å®äº:** ãŠãŒã¶ãŒã¯ã¢ãŒãã«ãéããŠãå
ã®ããŒãžé²èЧãç¶ããŸããããŒãã£ã³ã°è¡šç€ºã¯å
ã®ãã¿ã³è¡šç€ºã«æ»ããŸãã
#### 9.2.2. ãšããžã±ãŒã¹ã®å¯Ÿå¿
- **å£ã³ããå°ãªãå Žå:**
- **æ¡ä»¶:** DjangoåŽã§ã察象æœèšã®å£ã³ãã3ä»¶æªæºã®å Žåã
- **åŠç:** AIã®APIã¯åŒã³åºãããå³åº§ã«ãå£ã³ãã3ä»¶æªæºã®ãããèŠçŽã§ããŸãããããšããã¢ã©ãŒãã¡ãã»ãŒãžã衚瀺ããŸããããã«ãããäžèŠãªAPIã³ãŒã«ãé²ãããŠãŒã¶ãŒã«ç¶æ³ãç確ã«äŒããŸãã
- **APIãšã©ãŒçºçæ:**
- **æ¡ä»¶:** APIã®ã¿ã€ã ã¢ãŠãããµãŒããŒãšã©ãŒãçºçããå Žåã
- **åŠç:** ãAIãµãŒããŒã§åé¡ãçºçããŸãããæéããããŠå床ã詊ããã ãããããšãã£ãå
容ãã¢ã©ãŒããŸãã¯ã¢ãŒãã«ã§è¡šç€ºããŸãã
### 9.3. ããŒã¿åŠçã»ããžãã¹ããžãã¯èšèš (v1)
AIã®æ§èœãæå€§éã«åŒãåºããå®å®ããéçšãè¡ãããã®å
éšã«ãŒã«ã以äžã®ããã«èšèšããŸãã
#### 9.3.1. å
¥åããŒã¿ã®ååŠç (DjangoåŽ)
- **å£ã³ãã®çµå:** è€æ°ã®å£ã³ãã¯ããããããç¬ç«ããæ®µèœãšããŠAIã«èªèãããããã2ã€ã®æ¹è¡æå (`\n\n`) ã§åºåã£ãŠ1ã€ã®ããã¹ãã«çµåããŸãã
- **ãã€ãºé€å»:** çµµæåãURLãªã©ãèŠçŽã®ãã€ãºãšãªãããäžèŠãªæååã¯ãæ£èŠè¡šçŸãçšããŠäºåã«é€å»ããŸãã
#### 9.3.2. èŠçŽå®è¡ã®å€æããžã㯠(DjangoåŽ)
以äžã®æ¡ä»¶ãæºãããªãå Žåã¯ãAPIãåŒã³åºããã«ãšã©ãŒãšããŠåŠçããŸãã
- **æå°å£ã³ãä»¶æ°:** 3件以äž
- **æå°ç·æåæ°:** å
šäœã®æåæ°ã300æå以äž
#### 9.3.3. AIã¢ãã«ã®æšè«ãã©ã¡ãŒã¿ (Gradio APIåŽ)
çæãããèŠçŽæã®å質ãå¶åŸ¡ããããã以äžã®åæãã©ã¡ãŒã¿ãèšå®ããŸãããããã®å€ã¯ `config.py` ã§ç®¡çãã調æŽå¯èœã«ããŸãã
- **èŠçŽæã®æå°é· (`min_length`):** 50
- **èŠçŽæã®æå€§é· (`max_length`):** 250
- **é·ãããã«ã㣠(`length_penalty`):** 2.0 (åé·ãªè¡šçŸãæå¶)
#### 9.3.4. 倧éããŒã¿ãžã®å¯Ÿå¿æ¹é
- **åæå®è£
:** ãŸãã¯å
šãŠã®å£ã³ããçµåããŠAPIã«éä¿¡ããŸããã¢ãã«ã®æå€§å
¥åé·ãè¶
ããå Žåã¯ã`truncation=True` ãªãã·ã§ã³ã«ããèªåçã«æ«å°ŸãåãæšãŠãããŸãã
- **å°æ¥çãªæ¹å:** æ§èœãã³ã¹ãã«åé¡ãèŠãããå ŽåããçŽè¿1幎éã®å£ã³ãã®ã¿ã察象ãšããããªã©ã®å¶éãåŸãã远å ããããšãæ€èšããŸãã
### 9.4. ãšã©ãŒãã³ããªã³ã°èšèš (v1)
äºæãã¬äºæ
ãçºçããå Žåã§ãã·ã¹ãã ãå®å®ããŠåäœãããŠãŒã¶ãŒã«é©åãªãã£ãŒãããã¯ãè¿ããããã以äžã®éããšã©ãŒãã³ããªã³ã°ãèšèšããŸãã
#### 9.4.1. ãšã©ãŒçºçæºãšå¯Ÿå¿æ¹é
| çºçå Žæ | ãšã©ãŒäŸ | å¯Ÿå¿æ¹é | ãŠãŒã¶ãŒãžã®éç¥äŸ |
| :--- | :--- | :--- | :--- |
| **Gradio API** | ã¢ãã«ã®ããŒã倱æãæšè«äžã®ãšã©ãŒ | `try...except`ã§ææããHTTP 500ãšãšã©ãŒå
容ãJSONã§è¿ãã | (Djangoçµç±ã§)ãAIãµãŒããŒã§åé¡ãçºçã |
| **Django â Gradio APIé** | ãããã¯ãŒã¯é害ãã¿ã€ã ã¢ãŠã | Djangoã®`requests`éšåã§`try...except`ã§ææãããšã©ãŒããã°èšé²ã | ãAIãµãŒããŒã«å¿çããããŸããã |
| **Django** | DBæ¥ç¶ãšã©ãŒãå£ã³ãä»¶æ°äžè¶³ | `try...except`ãæ¡ä»¶åå²ã§å¯Ÿå¿ãå£ã³ãäžè¶³ã¯HTTP 400ãè¿ãã | ããµãŒããŒã§ãšã©ãŒãçºçãããŸãã¯ãå£ã³ããäžè¶³ã |
| **ãã©ãŠã¶ â Djangoé** | ãŠãŒã¶ãŒã®ãªãã©ã€ã³ | jQuery Ajaxã®`.fail()`ã³ãŒã«ããã¯ã§ææã | ãéä¿¡ã«å€±æããŸããã |
#### 9.4.2. å®è£
ã®ãã€ã³ã
- **Django (åžä»€å¡) ã®åœ¹å²:**
- Djangoã®ãã¥ãŒã¯ãGradio APIãšã®éä¿¡éšåãå¿
ã`try...except`ãããã¯ã§å²ã¿ãã¿ã€ã ã¢ãŠãïŒäŸ: 30ç§ïŒãèšå®ããŸãã
- APIããè¿ãããHTTPã¹ããŒã¿ã¹ã³ãŒããåžžã«ãã§ãã¯ãã200çªå°ä»¥å€ã¯ãšã©ãŒãšããŠåŠçããŸãã
- çºçãããšã©ãŒã¯ã**å¿
ããµãŒããŒãã°ã«èšé²**ããåå 調æ»ã«åœ¹ç«ãŠãŸãã
- ãŠãŒã¶ãŒã«ã¯ãæè¡çãªãšã©ãŒè©³çްïŒã¹ã¿ãã¯ãã¬ãŒã¹çïŒãçŽæ¥èŠããããAIãµãŒããŒã§åé¡ãçºçããŸãããã®ãããªæœè±¡çã§åãããããã¡ãã»ãŒãžãè¿ããŸãã
- **Gradio API (å°éå®¶) ã®åœ¹å²:**
- AIã®æšè«åŠçãªã©ã倱æããå¯èœæ§ã®ããã³ãŒãã¯`try...except`ãããã¯ã§å²ã¿ãŸãã
- ãšã©ãŒçºçæã¯ã`raise gr.Error("å
·äœçãªãšã©ãŒåå ")`ãåŒã³åºããAPIã®å¥çŽéãã«ãšã©ãŒæ
å ±ãè¿åŽããŸãã
### 9.5. 詳现èšèš: AIæšè«ã³ã¢ (`core/inference.py`) (v1)
AIæšè«ã®ã³ã¢ããžãã¯ã¯ãä¿å®æ§ãšãã¹ãå®¹ææ§ãé«ããããã«ãããã€ãã®èšèšååãšãã¶ã€ã³ãã¿ãŒã³ãé©çšããŠæ§é åããŸãã
#### 9.5.1. ã¯ã©ã¹èšèšãšè²¬å
- **`Summarizer` ã¯ã©ã¹ã®å°å
¥:** AIã®æšè«ã«é¢é£ããå
šãŠã®ããžãã¯ããåäžã®`Summarizer`ã¯ã©ã¹ã«éçŽããŸãããã®ã¯ã©ã¹ã¯**ãAIã¢ãã«ã管çããããã¹ãèŠçŽãå®è¡ããã**ãšããæç¢ºãªè²¬åãæã¡ãŸãã
#### 9.5.2. é©çšãããã¶ã€ã³ãã¿ãŒã³
- **ãã¡ãµãŒã (Facade) ãã¿ãŒã³:** `Summarizer`ã¯ã©ã¹ã¯ã`transformers`ã©ã€ãã©ãªã®è€éãªå
éšåŠçïŒã¢ãã«ã®ããŒããããŒã¯ãã€ãºãæšè«ããã³ãŒãçïŒãã«ãã»ã«åïŒé èœïŒããŸãããããŠã`summarize(text)`ãšããéåžžã«ã·ã³ãã«ãªã¡ãœããã®ã¿ãå€éšã«å
¬éããŸããããã«ãããå©çšåŽïŒ`main.py`ïŒã¯AIã®è€éãªè©³çްãæèããããšãªããç°¡åãã€å®å
šã«èŠçŽæ©èœãå©çšã§ããŸãã
- **äŸåæ§ã®æ³šå
¥ (Dependency Injection) ã«ããã€ã³ã¹ã¿ã³ã¹ç®¡ç:** AIã¢ãã«ã®ãããªãªãœãŒã¹ã倧éã«æ¶è²»ãããªããžã§ã¯ãã¯ããªã¯ãšã¹ãããšã«çæããã¹ãã§ã¯ãããŸããã代ããã«ãã¢ããªã±ãŒã·ã§ã³ã®èµ·åæã«äžåºŠã ã`Summarizer`ã®ã€ã³ã¹ã¿ã³ã¹ãçæãããããå¿
èŠãšããåã³ã³ããŒãã³ãïŒAPIã®ãšã³ããã€ã³ã颿°ãªã©ïŒã«**泚å
¥ïŒåŒæ°ãšããŠæž¡ãïŒ**ããŸãã
- **ãªãã·ã³ã°ã«ãã³ãé¿ããã:** ãææã®éããã°ããŒãã«ãªåäžã€ã³ã¹ã¿ã³ã¹ïŒã·ã³ã°ã«ãã³ïŒã«äŸåããèšèšã¯ãã³ã³ããŒãã³ãéã®çµåã匷ãããã¹ããå°é£ã«ããããã¢ã³ããã¿ãŒã³ãšèŠãªãããŸãããã®ã¢ãããŒãã¯é¿ããã¹ãã§ãã
- **å
·äœçãªå®çŸæ¹æ³:** ã¢ããªã±ãŒã·ã§ã³ã®ãšã³ããªãŒãã€ã³ãïŒ`main.py`ïŒã§`Summarizer`ã€ã³ã¹ã¿ã³ã¹ãçæãã`functools.partial`ãªã©ãçšããŠãAPIãåŠçãã颿°ã«ãã®ã€ã³ã¹ã¿ã³ã¹ããããããæž¡ããŠããããšã§ãã°ããŒãã«ãªç¶æ
ãæã€ããšãªãã€ã³ã¹ã¿ã³ã¹ã®å
±æãå®çŸããŸããããã«ããããã¹ãå®¹ææ§ãšèšèšã®æè»æ§ã倧å¹
ã«åäžããŸãã
- **èšå®å€ã®æ³šå
¥:** ãã®DIãã¿ãŒã³ã¯ã`Summarizer`ã¯ã©ã¹ã䜿çšããã¢ãã«åãèŠçŽã®é·ããšãã£ãèšå®å€ãã³ã³ã¹ãã©ã¯ã¿ãéããŠå€éšã®`config`ã¢ãžã¥ãŒã«ããåãåããšãããå
ã
ã®äŸåæ§æ³šå
¥ã®èãæ¹ãšãäžèŽããŠããŸãã
#### 9.5.3. ãšã©ãŒãã³ããªã³ã°æ¹é
- `Summarizer`ã¯ã©ã¹å
ã§çºçãããšã©ãŒïŒã¢ãã«ã®ããŒã倱æãæšè«å€±æãªã©ïŒã¯ãã¯ã©ã¹å
éšã§é©åã«ææãããåŒã³åºãå
ããã³ããªã³ã°ããããããã«ãå°çšã®äŸå€ïŒäŸ: `InferenceError`ïŒãšããŠåéåºããèšèšãšããŸãã
### 9.6. 詳现èšèš: èšå®ç®¡ç (`config.py`) (v1)
èšå®å€ãã³ãŒãããåé¢ããå®å
šãã€æ§é çã«ç®¡çããããã以äžã®éãèšèšããŸãã
#### 9.6.1. èšèšæ¹é
- **ããŒã¿ã¯ã©ã¹ã®æŽ»çš:** Pythonæšæºã®`dataclasses`ãçšããé¢é£ããèšå®é
ç®ãã°ã«ãŒãåããèšå®ã¯ã©ã¹ïŒäŸ: `ModelConfig`ïŒãå®çŸ©ããŸããããã«ãããåå®å
šæ§ãä¿èšŒãããã³ãŒãè£å®ãå¹ãããéçºå¹çãåäžããŸãã
- **äžå€æ§ã®ç¢ºä¿:** äœæããããŒã¿ã¯ã©ã¹ã¯ `@dataclass(frozen=True)` ãæå®ããã€ãã¥ãŒã¿ãã«ïŒå€æŽäžå¯èœïŒã«ããŸããããã«ãããã¢ããªã±ãŒã·ã§ã³å®è¡äžã«æå³ããèšå®ã倿ŽãããŠããŸãå±éºãªç¶æ
ãé²ããŸãã
- **ç°å¢å€æ°ã«ããèšå®ã®äžæžã:** å°æ¥çãªæ¡åŒµæ§ïŒäŸ: APIããŒã®ç®¡çïŒãèŠæ®ããèšå®å€ã¯ç°å¢å€æ°ããååŸããããšãåºæ¬ãšããŸããéçºç°å¢ã§ã¯`.env`ãã¡ã€ã«ãå©çšããæ¬çªç°å¢ã§ã¯å®è¡ç°å¢ïŒHugging Face Spacesãªã©ïŒã®Secretsæ©èœã§èšå®ã泚å
¥ããéçšãæ³å®ããŸãã
- **`.env.example` ã®æäŸ:** éçºè
ãç°å¢å€æ°ã容æã«èšå®ã§ããããããªããžããªã«ã¯ `.env.example` ãã¡ã€ã«ãå«ããŸããå®éã®éçºã§ã¯ããã®ãã¡ã€ã«ãã³ããŒã㊠`.env` ãäœæããå€ãèšå®ããŸãã
```.env.example
# AI APIã®ã¢ãã«åãæå®
AI_MODEL_NAME="llm-jp/t5-small-japanese-finetuned-sum"
```
- **`docker-compose.yml` ã§ã®èªã¿èŸŒã¿:** `docker-compose.yml` ãã¡ã€ã«ã§ `env_file` ãæå®ããããšã§ãã³ã³ããèµ·åæã« `.env` ãã¡ã€ã«ã®å
容ãç°å¢å€æ°ãšããŠèªã¿èŸŒãŸããŸãã
```yaml
services:
api:
build: .
env_file:
- .env
```
#### 9.6.2. æ§é æ¡
- **`ModelConfig` ã¯ã©ã¹:**
- **責å:** 䜿çšããAIã¢ãã«ã«é¢ããæ
å ±ãäžå
管çããŸãã
- **屿§æ¡:** `NAME` (ã¢ãã«å), `REVISION` (ããŒãžã§ã³)
- **`InferenceConfig` ã¯ã©ã¹:**
- **責å:** AIã®æšè«ïŒèŠçŽçæïŒæã®ãã©ã¡ãŒã¿ãäžå
管çããŸãã
- **屿§æ¡:** `MIN_LENGTH`, `MAX_LENGTH`, `LENGTH_PENALTY`, `NUM_BEAMS`
### 9.7. 詳现èšèš: DjangoåŽãã¥ãŒ (`summary_views.py`) (v1)
DjangoåŽã§AI APIãåŒã³åºããã¥ãŒã¯ã責åãæç¢ºã«åé¢ããå
ç¢ãªãšã©ãŒãã³ããªã³ã°ãšãã®ã³ã°ãçµã¿èŸŒãã ã¯ã©ã¹ãšããŠèšèšããŸãã
#### 9.7.1. èšèšæ¹é
- **ã¯ã©ã¹ããŒã¹ãã¥ãŒ (CBV) ã®æ¡çš:** Djangoæšæºã®`django.views.View`ãç¶æ¿ããã¯ã©ã¹ãšããŠå®è£
ããŸããããã«ãããå°æ¥çãªæ©èœæ¡åŒµïŒäŸ: POSTã¡ãœããã®è¿œå ïŒã«ãæè»ã«å¯Ÿå¿ã§ããŸãã
- **責åã®åé¢:** 1ã€ã®ã¡ãœããã«å
šãŠã®ããžãã¯ãèšè¿°ããã®ã§ã¯ãªãããå£ã³ãã®ååŸããããªããŒã·ã§ã³ããAPIåŒã³åºãããšãã£ãé¢å¿äºããšã«ãã©ã€ããŒãã¡ãœããïŒäŸ: `_call_api`ïŒãžåŠçãåå²ããã¡ã€ã³ã®`get`ã¡ãœããã®èŠéããè¯ãããŸãã
- **éäžçãªãšã©ãŒãã³ããªã³ã°:** ã¡ã€ã³ã®`get`ã¡ãœããã«`try...except`ãããã¯ãèšããååŠçã§çºçãããäŸå€ïŒDBé¢é£ãéä¿¡é¢é£ãªã©ïŒãéäžçã«ææããé©åãª`JsonResponse`ãè¿ãããã«ããŸãã
- **詳现ãªãã®ã³ã°:** Pythonã®`logging`ã¢ãžã¥ãŒã«ã掻çšããAPIåŒã³åºãã®æåŠãçºçãããšã©ãŒãããžãã¹ããžãã¯ã®å€æãªã©ããã°ã«åºåããŸããç¹ã«ãšã©ãŒçºçæã«ã¯ãã¹ã¿ãã¯ãã¬ãŒã¹ãå«ããŠèšé²ããããšã§ãè¿
éãªåå ç©¶æãå¯èœã«ããŸãã
#### 9.7.2. ã¯ã©ã¹ã»ã¡ãœããæ§ææ¡
- **`SummarizeReviewsView(View)`**
- **`get(self, request, playground_id)`:**
- HTTP GETãªã¯ãšã¹ããåŠçããã¡ã€ã³ã¡ãœããã
- 以äžã®åŠçãããŒãå¶åŸ¡ããã
1. `_get_reviews`ãåŒã³åºããå£ã³ãããŒã¿ãååŸã
2. `_validate_reviews`ãåŒã³åºããããžãã¹ã«ãŒã«ïŒä»¶æ°ãæåæ°ïŒãæ€èšŒã
3. å£ã³ãããã¹ããååŠçïŒçµåããã€ãºé€å»ïŒã
4. `_call_summary_api`ãåŒã³åºããå€éšAPIãšéä¿¡ã
5. æåã¬ã¹ãã³ã¹ãŸãã¯ãšã©ãŒã¬ã¹ãã³ã¹ã`JsonResponse`ãšããŠè¿ãã
- **`_get_reviews(self, playground_id)`:**
- `playground_id`ã«å¯Ÿå¿ããå£ã³ããããŒã¿ããŒã¹ããååŸãã責åãæã€ã
- **`_validate_reviews(self, reviews)`:**
- ååŸããå£ã³ããèŠçŽå®è¡ã®æ¡ä»¶ãæºãããæ€èšŒãã責åãæã€ã
- **`_call_summary_api(self, text)`:**
- `requests`ã©ã€ãã©ãªã䜿ããGradio APIãšã®éä¿¡ãè¡ã責åãæã€ãã¿ã€ã ã¢ãŠãèšå®ãããã§è¡ãã
#### 9.7.3. èšå®å€ã®ç®¡ç
- Gradio APIã®ãšã³ããã€ã³ãURLãã¿ã€ã ã¢ãŠãç§æ°ãšãã£ãèšå®å€ã¯ã`settings.py`ã«èšè¿°ãããã¥ãŒããã¯`django.conf.settings`ãéããŠåç
§ããŸããããã«ãããèšå®ã®äžå
管çãå®çŸããŸãã
### 9.8. 詳现èšèš: ãã¹ãæŠç¥ã®å
·äœå (v1)
ã¢ããªã±ãŒã·ã§ã³ã®å質ãšä¿¡é Œæ§ãä¿èšŒããããã以äžã®éãå€å±€çãªãã¹ãæŠç¥ãèšèšããŸãã
#### 9.8.1. ãã¹ãã®çš®é¡ãšç®ç
- **ãŠããããã¹ã (Unit Tests):**
- **ç®ç:** åã
ã®éšåïŒã¯ã©ã¹ãã¡ãœããïŒãåäœã§æ£ããåäœããããšãæ€èšŒããŸããé«éã«å®è¡ã§ãããããéçºäžã®é »ç¹ãªç¢ºèªã«é©ããŠããŸãã
- **察象:** `core/inference.py` ã® `Summarizer` ã¯ã©ã¹ãªã©ãããžãã¹ããžãã¯ã®äžæ žãæ
ãéšåã
- **ã€ã³ãã°ã¬ãŒã·ã§ã³ãã¹ã (Integration Tests):**
- **ç®ç:** Gradio APIã®ãšã³ããã€ã³ãããAPIã®å¥çŽéãã«æ£ãããªã¯ãšã¹ããåŠçããã¬ã¹ãã³ã¹ãè¿ãããšãæ€èšŒããŸããã³ã³ããŒãã³ãéã®é£æºã確èªããŸãã
- **察象:** ããŒã«ã«ã§èµ·åããGradioã¢ããªã±ãŒã·ã§ã³ã® `/api/predict/` ãšã³ããã€ã³ãã
#### 9.8.2. ãã¹ãã±ãŒã¹ã®èšç»
- **ãŠããããã¹ã (`tests/core/test_inference.py`):**
- **æ£åžžç³»:** éåžžã®ããã¹ããå
¥åãããå Žåã«ãæåŸ
ããã圢åŒïŒæååïŒã®èŠçŽãè¿ãããšã確èªããã
- **ç°åžžç³»:** 空æååãäžæ£ãªããŒã¿åãå
¥åãããå Žåã«ãèšèšéã`ValueError`çã®äŸå€ãçºçããããšã確èªããã
- **ã€ã³ãã°ã¬ãŒã·ã§ã³ãã¹ã (`tests/test_api.py`):**
- **æ£åžžç³»:** APIã«æå¹ãªãªã¯ãšã¹ããéä¿¡ããHTTPã¹ããŒã¿ã¹ã³ãŒã`200`ãšãèšèšéãã®JSONã¬ã¹ãã³ã¹ãè¿ãããšã確èªããã
- **ç°åžžç³»:** äžæ£ãªãªã¯ãšã¹ããéä¿¡ããå Žåã«ãé©åãªHTTPãšã©ãŒã¹ããŒã¿ã¹ã³ãŒãïŒäŸ: `4xx`ïŒãè¿ãããšã確èªããã
#### 9.8.3. ãã¹ãã®å¹çå
- **ãã£ã¯ã¹ãã£ã®æŽ»çš (`@pytest.fixture`):** AIã¢ãã«ã®ããŒãã¯æéããããããã`Summarizer`ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹çæããã£ã¯ã¹ãã£ãšããŠå®çŸ©ããŸãã`scope="session"`ãæå®ããããšã§ãå
šãã¹ãå®è¡äžã«ã¢ãã«ã®ããŒããäžåºŠã ãã§æžã¿ããã¹ãæéã倧å¹
ã«ççž®ããŸãã
- **ãã©ã¡ãŒã¿åã®æŽ»çš (`@pytest.mark.parametrize`):** è€æ°ã®ç°ãªãå
¥åå€ãšæåŸ
ãããçµæã®çµã¿åããããäžã€ã®ãã¹ã颿°ã§å¹ççã«æ€èšŒããããã«äœ¿çšããŸãã
### 9.9. 詳现èšèš: Django-AI飿º (v1)
Djangoã¢ããªã±ãŒã·ã§ã³ãšAIã¢ããªã±ãŒã·ã§ã³ïŒGradioïŒãã©ã®ããã«é£æºããŠæ©èœãå®çŸãããã®å
·äœçãªèšèšã以äžã«ç€ºããŸãã
#### 9.9.1. 飿ºã·ãŒã±ã³ã¹
##### æ£åžžç³»ã®ã·ãŒã±ã³ã¹
å
šäœã®åŠçã®æµãã¯ä»¥äžã®éãã§ãã
```mermaid
sequenceDiagram
participant Browser as ãŠãŒã¶ãŒ(ãã©ãŠã¶)
participant Django as DjangoãµãŒããŒ
participant Gradio as AI API (Gradio)
Browser->>+Django: GET /summarize/playground/{id}/
Django->>Django: 1. å£ã³ãååŸã»æ€èšŒ
alt å£ã³ãã3ä»¶æªæºãªã©æ¡ä»¶ãæºãããªã
Django-->>-Browser: JSON (ãšã©ãŒ)
end
Django->>+Gradio: POST /api/predict/ (å£ã³ãããã¹ã)
Gradio->>Gradio: 2. AIã¢ãã«ã§èŠçŽå®è¡
Gradio-->>-Django: JSON (èŠçŽçµæ)
Django-->>-Browser: JSON (èŠçŽçµæ)
```
##### ç°åžžç³»ïŒAI APIãšã©ãŒïŒã®ã·ãŒã±ã³ã¹
AI APIåŽã§ãšã©ãŒãçºçããå Žåã®åŠçã®æµãã§ãã
```mermaid
sequenceDiagram
participant Browser as ãŠãŒã¶ãŒ(ãã©ãŠã¶)
participant Django as DjangoãµãŒããŒ
participant Gradio as AI API (Gradio)
Browser->>+Django: GET /summarize/playground/{id}/
Django->>+Gradio: POST /api/predict/ (å£ã³ãããã¹ã)
Gradio->>Gradio: AIã¢ãã«ã®åŠçã§ãšã©ãŒçºç
Gradio-->>-Django: HTTP 500 (ãšã©ãŒæ
å ±)
Django->>Django: ãšã©ãŒããã°ã«èšé²
Django-->>-Browser: JSON (ãŠãŒã¶ãŒåããšã©ãŒã¡ãã»ãŒãž)
```
#### 9.9.2. åã³ã³ããŒãã³ãã®è²¬åãšå®è£
**1. DjangoåŽ (`myapp/views/summary_views.py`)**
- **ã¯ã©ã¹:** `SummarizeReviewsView(View)`
- **ã¡ãœãã:** `get(self, request, playground_id)`
- **責å:** ãªã¯ãšã¹ããåãä»ããAI APIãšã®éä¿¡ãå¶åŸ¡ããåžä»€å¡ã
- **åŠçãããŒ:**
1. DBããå£ã³ããååŸããä»¶æ°ãæåæ°ãæ€èšŒããã
2. `_call_summary_api` ã¡ãœãããåŒã³åºããAI APIã«ãªã¯ãšã¹ããéä¿¡ããã
3. è¿ã£ãŠããçµæïŒæåãŸãã¯ãšã©ãŒïŒãæŽåœ¢ãã`JsonResponse`ãšããŠããã³ããšã³ãã«è¿ãã
- **ã¡ãœãã:** `_call_summary_api(self, text)`
- **責å:** `requests`ã©ã€ãã©ãªãçšããŠãAI APIãšã®HTTPéä¿¡ãå®éã«æ
åœããã
- **å®è£
詳现:**
- `settings.AI_SUMMARY_API_URL` ããAPIã®ãšã³ããã€ã³ãURLãååŸããã
- `requests.post()` ã䜿ããã¿ã€ã ã¢ãŠããèšå®ããŠPOSTãªã¯ãšã¹ããéä¿¡ããã
- éä¿¡ãšã©ãŒããAPIãè¿ããšã©ãŒã¹ããŒã¿ã¹ã³ãŒãã`try...except`ã§ææããé©åã«åŠçããã
- æåæã¯ã¬ã¹ãã³ã¹ã®JSONãããŒã¹ããèŠçŽããã¹ããè¿ãã
**2. AIã¢ããªã±ãŒã·ã§ã³åŽ (`src/ai_api/`)**
- **ãã¡ã€ã«:** `main.py` (ãšã³ããªãŒãã€ã³ã)
- **責å:** Gradioã¢ããªã±ãŒã·ã§ã³ãèµ·åããHTTPãªã¯ãšã¹ããåãä»ããçªå£ã
- **å®è£
詳现:**
1. èµ·åæã«äžåºŠã ãã`core.inference.Summarizer` ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãçæããã
2. `functools.partial` ã䜿ããAPIåŠç颿°ã« `Summarizer` ã®ã€ã³ã¹ã¿ã³ã¹ã泚å
¥ïŒãã€ã³ãïŒããã
3. `gradio.Interface` ãå®çŸ©ãããªã¯ãšã¹ããåŠçãã颿°ãšããŠäžèšã§ãã€ã³ããã颿°ãæž¡ããããã«ãããGradio㯠`/api/predict/` ãšãããšã³ããã€ã³ããèªåçã«äœæããã
- **ãã¡ã€ã«:** `core/inference.py`
- **ã¯ã©ã¹:** `Summarizer`
- **ã¡ãœãã:** `summarize(self, text)`
- **責å:** AIã¢ãã«ã®ç®¡çãšãå®éã®èŠçŽåŠçãšããã³ã¢ããžãã¯ã«è²¬ä»»ãæã€ã
- **å®è£
詳现:** `transformers`ã©ã€ãã©ãªã䜿ããããã¹ãã®ããŒã¯ãã€ãºãã¢ãã«ã«ããæšè«ãçµæã®ãã³ãŒããè¡ãã
#### 9.9.3. ççµåã®æ
ä¿ïŒç¬ç«ããéçºã»ãã¹ãïŒ
ãã®èšèšããããã«ããŠççµåïŒLoose CouplingïŒãæ
ä¿ããŠãããã以äžã«ç€ºããŸãã
- **éä¿¡ã®æœè±¡å:**
- DjangoãšAIã¢ããªã¯ã**HTTPãšJSON**ãšããæšæºåãããæè¡ã§ã®ã¿éä¿¡ããŸãã
- Djangoã¯AIã¢ããªãGradioã§å®è£
ãããŠããããšãç¥ãå¿
èŠã¯ãªããéããŸãç¶ãã§ããç¥ã£ãŠããã®ã¯ãã©ã®URLã«ãã©ããªJSONãéãã°ãã©ããªJSONãè¿ã£ãŠãããããšããAPIå¥çŽã ãã§ãã
- **ç¬ç«ããå®è¡ãšãã¹ã:**
- **AIã¢ããªã±ãŒã·ã§ã³:**
- `src/ai_api/` ãã£ã¬ã¯ããªã¯ãããèªäœãå®çµããPythonãããžã§ã¯ãã§ãã
- `python src/ai_api/main.py` ãå®è¡ããã°ãDjangoãšã¯ç¡é¢ä¿ã«åäœã§èµ·åã§ããŸãã
- èµ·åããAIã¢ããªã«å¯Ÿãããã©ãŠã¶ã§UIãæäœãããã`curl`ã³ãã³ãã§APIãçŽæ¥å©ãããããããšã§ãåäœã§ã®åäœãã¹ããå¯èœã§ãã
- **Djangoã¢ããªã±ãŒã·ã§ã³:**
- `SummarizeReviewsView` ã®ãã¹ããæžãéã`unittest.mock.patch` ã䜿ã£ãŠ `_call_summary_api` ã¡ãœãããã¢ãã¯ïŒåœã®ãªããžã§ã¯ãã«å·®ãæ¿ãïŒããŸãã
- ããã«ãããAI APIãžå®éã«ãããã¯ãŒã¯éä¿¡ãçºçãããããšãªãããAPIãæåãè¿ããå Žåããã¿ã€ã ã¢ãŠãããå Žåãããšã©ãŒãè¿ããå Žåããªã©ãããããç¶æ³ãæ³å®ãããã¥ãŒã®ããžãã¯ãé«éã«ãã¹ãã§ããŸãã
ãã®èšèšã«ãããäž¡ã¢ããªã±ãŒã·ã§ã³ã¯äºãã«äŸåããããšãªããç¬ç«ããŠéçº,ãã¹ã,ãããã€ãé²ããããšãå¯èœã«ãªããŸãã
### 9.10. pyproject.toml ã®è©³çްèšèš
ããã§ã®ãŽãŒã«ã¯ããããžã§ã¯ãã§å©çšããå質管çããŒã«ïŒRuff, Mypy, PytestïŒã®å
·äœçãªåäœã«ãŒã«ã`pyproject.toml`ãã¡ã€ã«ã«å®çŸ©ãã誰ãéçºããŠãããŸãCI/CDã§å®è¡ãããŠããåžžã«äžè²«ããåºæºã§ã³ãŒãã®å質ããã§ãã¯ãããããã«ããããšã§ãã
#### 1. Ruff (ãªã³ã¿ãŒ & ãã©ãŒããã¿ãŒ)
é«éãªãªã³ã¿ãŒå
Œãã©ãŒããã¿ãŒã§ããRuffã®èšå®ãå®çŸ©ããŸãã
##### èšèšæ¹é
- Pythonã®æšæºçãªãã©ãŒããã¿ãŒã§ãã`black`ã®èŠçŽã«æºæ ãããŸãã
- å¿
é ã®ã«ãŒã«ã«å ããæœåšçãªãã°ãçºèŠããã«ãŒã«ããã³ãŒããããã¢ãã³ãªèšæ³ã«èªåä¿®æ£ããã«ãŒã«ãç©æ¥µçã«æå¹åããã³ãŒãå質ãé«ãä¿ã¡ãŸãã
##### èšå®æ¡ (`[tool.ruff]`ã»ã¯ã·ã§ã³)
- `line-length = 88`: 1è¡ã®æå€§é·ã`black`ã«åãããŠ88æåã«èšå®ã
- `select = ["E", "W", "F", "I", "B", "UP"]`:
- `E`, `W`, `F`: `pycodestyle`ãš`Pyflakes`ã®åºæ¬çãªãšã©ãŒã»èŠåïŒå¿
é ïŒã
- `I`: `isort`äºæã®importæã®èªåãœãŒãïŒå¿
é ïŒã
- `B`: `flake8-bugbear`ã®ããã°ã®æž©åºãšãªããããã³ãŒããã¿ãŒã³ãæ€åºããã«ãŒã«ã
- `UP`: `pyupgrade`ã®ãå€ãPythonèšæ³ãæ°ããèšæ³ãžèªåçã«ã¢ããã°ã¬ãŒãããã«ãŒã«ã
- `target-version = "py312"`: Python 3.12ã®ææ³ãæ£ããè§£éããããã«æå®ã
##### èšå®æ¡ (`[tool.ruff.format]`ã»ã¯ã·ã§ã³)
- `quote-style = "double"`: ã³ãŒãå
ã§ã®åŒçšç¬Šãããã«ã¯ã©ãŒãïŒ`"`ïŒã«çµ±äžã
#### 2. Mypy (éçåãã§ãã«ãŒ)
åãã³ãã®æ£ãããä¿èšŒããMypyã®èšå®ãã峿 Œãã€å®çšçã«å®çŸ©ããŸãã
##### èšèšæ¹é
- åãã³ãã®èšè¿°ããããžã§ã¯ãå
ã§åŸ¹åºãããåã®å®å
šæ§ãé«ããŸãã
- äžæ¹ã§ãåæ
å ±ãæããªãå€éšã©ã€ãã©ãªã«èµ·å ãããšã©ãŒã¯ç¡èŠããå®çšæ§ãæãªããªãããã«ããŸãã
##### èšå®æ¡ (`[tool.mypy]`ã»ã¯ã·ã§ã³)
- `python_version = "3.12"`: åãã§ãã¯ã®å¯Ÿè±¡ãšãªãPythonããŒãžã§ã³ãæå®ã
- `ignore_missing_imports = true`: åæ
å ±ïŒã¹ã¿ãïŒãæäŸãããŠããªãã©ã€ãã©ãªãã€ã³ããŒãããéã®ãšã©ãŒãç¡èŠããŸããããã¯å€ãã®ãããžã§ã¯ãã§å¿
é ã®èšå®ã§ãã
- `disallow_untyped_defs = true`: åãã³ããæžãããŠããªã颿°å®çŸ©ããšã©ãŒãšããŸããããã«ããããããžã§ã¯ãå
šäœã§åãã³ãã®èšè¿°ã匷å¶ããã³ãŒãã®å¯èªæ§ãšä¿¡é Œæ§ãé£èºçã«åäžãããŸãã
- `warn_return_any = true`: 颿°ã®è¿ãå€ã®åããææ§ãª`Any`åã«ãªã£ãŠããå Žåã«èŠåãåºããŸããããå
·äœçãªåå®çŸ©ãä¿ãããã°ãæªç¶ã«é²ããŸãã
#### 3. Pytest (ãã¹ããã¬ãŒã ã¯ãŒã¯)
ãã¹ãã®å®è¡æ¹æ³ã«é¢ããèšå®ãå®çŸ©ããŸãã
##### èšèšæ¹é
- ãã¹ãã®å®è¡ã«é¢ããåºæ¬çãªã«ãŒã«ãå®ãã誰ãå®è¡ããŠãåãçµæãåŸãããããã«ããŸãã
##### èšå®æ¡ (`[tool.pytest.ini_options]`ã»ã¯ã·ã§ã³)
- `testpaths = ["tests"]`: ãã¹ããã¡ã€ã«ãæ ŒçŽãããŠãããã£ã¬ã¯ããªã`tests`ã«éå®ããŸãã
- `addopts = "-ra --strict-markers"`: ãã¹ãå®è¡æã«ã詳现ãªãµããªãŒã衚瀺ã(`-ra`)ãæªå®çŸ©ã®ãã¹ãããŒã«ãŒã®äœ¿çšãçŠæ¢ãã(`--strict-markers`)ããšã§ããã¹ãã®ç®¡çã峿 Œã«ããŸãã
- `minversion = "7.0"`: ãããžã§ã¯ããèŠæ±ããPytestã®æäœããŒãžã§ã³ã7.0ãšå®ããå€ãããŒãžã§ã³ã§ã®æå³ããªãåäœãé²ããŸãã
## 10. ãããªãæ€èšäºé
(Further Considerations)
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãv1éçºã®ã¹ã³ãŒãå€ãšãã€ã€ããæ¬æ©èœã®å質ãšäŸ¡å€ãç¶ç¶çã«åäžãããããã«ãå°æ¥çã«èª¿æ»ã»å®è£
ãã¹ãé
ç®ãèšç»ãšããŠãŸãšããã
### 10.1. AIã¢ãã«ã®è©äŸ¡ãšæ¹åãµã€ã¯ã« (MLOps)
**ç®ç:** æèŠçãªå€æãæããããŒã¿ã«åºã¥ããŠAIã®å質ã客芳çã«è©äŸ¡ã»æ¹åããä»çµã¿ãæ§ç¯ããã
| é
ç® | 調æ»èšç» | ææç© |
| : | : | : |
| **1. 客芳çè©äŸ¡ææšã®å°å
¥** | - èŠçŽã¿ã¹ã¯ã§äžè¬çã«å©çšãããè©äŸ¡ææšïŒROUGE, BERTScoreãªã©ïŒã調æ»ããã<br>- Pythonã®`evaluate`ã©ã€ãã©ãªçã䜿ãããµã³ãã«ããŒã¿ã§å®éã«ã¹ã³ã¢ãç®åºããPoCïŒæŠå¿µå®èšŒïŒãè¡ãã<br>- ã¹ã³ã¢ã®èšç®æ¹æ³ãšããã®çµæã®è§£éã«ã€ããŠç¥èŠããŸãšããã | - è©äŸ¡ææšã®éžå®çç±ãšäœ¿ãæ¹ããŸãšããããã¥ã¡ã³ãã<br>- ã¹ã³ã¢ç®åºçšã®ãµã³ãã«ã¹ã¯ãªããã |
| **2. ããã³ãããšã³ãžãã¢ãªã³ã°** | - ãããžãã£ã/ãã¬ãã£ãåæããç®æ¡æžãããªã©ãè€æ°ã®æç€ºïŒããã³ããïŒåœ¢åŒãèæ¡ããã<br>- åãå
¥åããŒã¿ã«å¯Ÿããåããã³ããã§çæçµæãã©ãå€ããããæ¯èŒã»åæããã<br>- æãèŠçŽã®è³ªãåäžããããã³ããã®ãã³ãã¬ãŒããæ±ºå®ããã | - ããã³ããã®æ¯èŒå®éšã®çµæã¬ããŒãã<br>- æ¡çšããããã³ãããã³ãã¬ãŒãã |
| **3. ã¢ãã«ã®A/Bãã¹ã** | - ç°ãªãã¢ãã«ãããã³ããã®æ§èœãå®ç°å¢ã§æ¯èŒããããã®A/Bãã¹ãåºç€ãæ€èšããã<br>- ãªã¯ãšã¹ãã«å¿ããŠãããã¯ãšã³ãã§ã¢ãã«ãåçã«åãæ¿ããä»çµã¿ãèšèšããã<br>- ãŠãŒã¶ãŒãã£ãŒãããã¯ãããžãã¹ææšïŒäŸ: æ»åšæéïŒãžã®åœ±é¿ãèšæž¬ããæé©ãªã¢ãã«ãéžå®ããã | - A/Bãã¹ãã®èšèšæžã<br>- ã¢ãã«åãæ¿ãããžãã¯ã®å®è£
æ¡ã |
| **4. ã¢ãã«æŽæ°æ¹éã®çå®** | - æ°ããæ¥æ¬èªèŠçŽã¢ãã«ãç»å Žããéã«ãã©ã®ã¿ã€ãã³ã°ã§è©äŸ¡ã»å°å
¥ãè¡ããã®åºæºãèšããã<br>- ãå幎ã«äžåºŠãææ°ã¢ãã«ã調æ»ããããç¹å®ã®è©äŸ¡ææšã10%ä»¥äžæ¹åããå Žåã«æŽæ°ãæ€èšããããªã©ãå
·äœçãªã«ãŒã«ãå®çŸ©ããã | - ã¢ãã«ã®ã©ã€ããµã€ã¯ã«ç®¡çæ¹éæžã |
### 10.2. å
ç¢æ§ãšã¹ã±ãŒã©ããªãã£ã®åäž
**ç®ç:** 倧éã¢ã¯ã»ã¹ãäºæãã¬å
¥åã«å¯ŸããŠããå®å®ããŠé«éãªã¬ã¹ãã³ã¹ãè¿ããã³ã¹ããæé©åããã
| é
ç® | 調æ»èšç» | ææç© |
| : | : | : |
| **1. é«åºŠãªå
¥åå岿Šç¥** | - é·å€§ãªå£ã³ã矀ã«å¯Ÿå¿ãããããããã¹ããæå³ã®ããåäœïŒãã£ã³ã¯ïŒã§åå²ãããããããèŠçŽããŠããæçµçã«çµ±åãããMap-Reduceãçãªã¢ãããŒãã調æ»ã»å®è£
ããã<br>- LangChainãªã©ã®ã©ã€ãã©ãªãæäŸããèŠçŽãã§ãŒã³ã®æŽ»çšãæ€èšããã | - ãã£ã³ã¯èŠçŽã®å®è£
PoCã<br>- é·æå
¥åã«å¯Ÿãããšã©ãŒçãåè³ªã®æ¹åã¬ããŒãã |
| **2. éåæAPIåŒã³åºã** | - DjangoããAI APIãåŒã³åºãåŠçãéåæåããWebãµãŒããŒã®ã¯ãŒã«ãŒã¹ã¬ãããé·æéãããã¯ããã®ãé²ãã<br>- CeleryãDramatiqãšãã£ãéåæã¿ã¹ã¯ãã¥ãŒãå°å
¥ããèŠçŽåŠçãããã¯ã°ã©ãŠã³ããžã§ããšããŠå®è¡ããã¢ãŒããã¯ãã£ãèšèšããã<br>- ããã³ããšã³ãåŽã¯ãããŒãªã³ã°ãWebSocketãå©çšããŠããžã§ãã®å®äºãæ€ç¥ãçµæã衚瀺ããæ¹åŒã«å€æŽããã | - éåæåŠçã¢ãŒããã¯ãã£ã®èšèšå³ã<br>- Celeryå°å
¥ã®PoCãšãå¿çæ§èœã®æ¹åå¹ææž¬å®ã¬ããŒãã |
| **3. ãã£ãã·ã¥æŠç¥ã®å°å
¥** | - Djangoã®ãã£ãã·ã¥ãã¬ãŒã ã¯ãŒã¯ïŒRedis, Memcachedãªã©ïŒã®å©ç𿹿³ã調æ»ããã<br>- ãæœèšIDããããŒãšããŠèŠçŽçµæããã£ãã·ã¥ããã¢ãŒããã¯ãã£ãèšèšããã<br>- ãã£ãã·ã¥ã®æå¹æéïŒTTLïŒãã©ã®çšåºŠã«èšå®ãã¹ãããæ¹éãæ±ºå®ããã | - ãã£ãã·ã¥ã·ã¹ãã ã®ã¢ãŒããã¯ãã£å³ã<br>- `settings.py`ãžã®èšå®äŸãšããã¥ãŒã§ã®å©çšã³ãŒãäŸã |
| **4. ã³ã¹ãã»ããã©ãŒãã³ã¹è©Šç®** | - Hugging Face Spacesã®ç¡ææ ã»ææãã©ã³ïŒããŒããŠã§ã¢æ§èœïŒãšæéäœç³»ã調æ»ããã<br>- 1ãªã¯ãšã¹ããããã®å¹³ååŠçæéãšã¡ã¢ãªäœ¿çšéãèšæž¬ããç¡ææ ã®ç¯å²å
ã§äœãªã¯ãšã¹ããŸã§åŠçå¯èœã詊ç®ããã<br>- æ³å®ãããã¢ã¯ã»ã¹æ°ã«åºã¥ããæéã®éçšã³ã¹ããšãã¹ã±ãŒã«ã¢ãããå¿
èŠã«ãªãæ¡ä»¶ãå®çŸ©ããã | - ã³ã¹ããšããã©ãŒãã³ã¹ã®è©Šç®ã¬ããŒãã<br>- ã¹ã±ãŒã«ã¢ããèšç»ã |
### 10.3. éçšãšç£èŠ
**ç®ç:** æ¬çªç°å¢ã«ãããAPIã®çšŒåç¶æ³ãå¯èŠåããåé¡çºçæã«è¿
éãªæ€ç¥ãšå¯Ÿå¿ãå¯èœã«ããã
| é
ç® | 調æ»èšç» | ææç© |
| : | : | : |
| **1. ãã°ã®çµ±å管ç** | - DjangoãšGradio APIã®äž¡æ¹ã§ããªã¯ãšã¹ãIDãå
±æããä»çµã¿ãå°å
¥ããã<br>- æ§é åãã°ïŒJSON圢åŒïŒã«ãªã¯ãšã¹ãIDãå«ããããšã§ãDatadogãªã©ã®å€éšãµãŒãã¹ã§ããŠãŒã¶ãŒãªã¯ãšã¹ãããAI APIåŒã³åºããŸã§ã®äžé£ã®ãã°ã暪æçã«è¿œè·¡ã§ããããã«ããã | - ãã°ãã©ãŒãããã®çµ±äžä»æ§ã<br>- æ§é åãã®ã³ã°ã®å®è£
äŸã |
| **2. ããã©ãŒãã³ã¹ç£èŠãšãšã©ãŒã¬ããŒã** | - Hugging Face Spacesãæšæºã§æäŸããåææ©èœïŒAnalyticsïŒã§ååŸã§ããã¡ããªã¯ã¹ã確èªããã<br>- Sentryãªã©ã®ãšã©ãŒã¬ããŒãããŒã«ãå°å
¥ããã¢ããªã±ãŒã·ã§ã³äŸå€ãèªåã§åéã»éç¥ããä»çµã¿ãæ§ç¯ããã<br>- ç¹ã«ç£èŠãã¹ãéèŠææšïŒKPIïŒãå®çŸ©ããïŒäŸ: ãšã©ãŒçã95ããŒã»ã³ã¿ã€ã«å¿çæéãèŠçŽå質ã¹ã³ã¢ïŒã | - ç£èŠããŒã«ã®éžå®ãšæ¯èŒã<br>- ç£èŠKPIãªã¹ããšãã®éŸå€ã®å®çŸ©ã<br>- Sentryå°å
¥æé æžã |
### 10.4. ãŠãŒã¶ãŒäœéšã®åŒ·å
**ç®ç:** AIã®æ©èœããããŠãŒã¶ãŒãã¬ã³ããªãŒã§ãå€ãã®äººãå©çšããããåœ¢ã§æäŸããã
| é
ç® | 調æ»èšç» | ææç© |
| : | : | : |
| **1. ãŠãŒã¶ãŒãã£ãŒãããã¯æ©æ§** | - èŠçŽçµæã«ã圹ã«ç«ã£ãã (ð/ð)ããæç¥šã§ããUIãèšèšããã<br>- ãã£ãŒãããã¯çµæãDjangoã®DBã«ä¿åããããã®ããŒã¿ã¢ãã«ãèšèšããã<br>- åéããããŒã¿ãå°æ¥ã®ã¢ãã«ååŠç¿ãããã³ããæ¹åã«ã©ã掻ããããæ¹éãæ€èšããã | - UIãã¶ã€ã³æ¡ã<br>- `models.py`ã«è¿œå ãããã£ãŒãããã¯ã¢ãã«ã®å®çŸ©ã<br>- ããŒã¿æŽ»çšæ¹éã®æŠèŠã |
| **2. åèŠçŽæ©èœ** | - ãŠãŒã¶ãŒãçæãããèŠçŽã«æºè¶³ããªãã£ãå Žåã«ãç°ãªããã©ã¡ãŒã¿ïŒäŸ: ããçãããã詳ããïŒã§åçæã詊ããUIãèšèšããã<br>- ãèŠçŽã®ããŒã³ãå€ããïŒäŸ: ä¿è·è
åããåäŸåãïŒããšãã£ãä»å æ©èœã®å®çŸå¯èœæ§ã調æ»ããã | - åèŠçŽæ©èœã®UIãã¶ã€ã³æ¡ã<br>- ãã©ã¡ãŒã¿å€æŽæ©èœã®å®è£
æ¹éã |
| **3. ã¢ã¯ã»ã·ããªã㣠(a11y) 察å¿** | - ã¢ãŒãã«è¡šç€ºããã¿ã³æäœããã¹ã¯ãªãŒã³ãªãŒããŒïŒèŠèŠé害è
åãèªã¿äžããœããïŒã§æ£ããèªèã»æäœã§ãããæ€èšŒããã<br>- WCAG (Web Content Accessibility Guidelines) ã®äž»èŠãªé
ç®ã«åºã¥ããããŒããŒãã®ã¿ã§ã®æäœãå¯èœããååãªã³ã³ãã©ã¹ãæ¯ã確ä¿ãããŠããããªã©ã確èªããã | - ã¢ã¯ã»ã·ããªãã£ã®ãã§ãã¯ãªã¹ãã<br>- 察å¿ãå¿
èŠãªç®æã®ä¿®æ£æ¡ã |
## 11. å®è£
ã¿ã¹ã¯ãªã¹ãïŒè©³çްçïŒ
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãTDDïŒãã¹ãé§åéçºïŒã®ãµã€ã¯ã«ã«åºã¥ããå®è£
ã®è©³çŽ°ãªæé ãéå±€çã«å®çŸ©ããŸãã
- **æ
åœ: AI** - ãã®ã¢ã€ã³ã³ãä»ããŠããã¿ã¹ã¯ã¯ãAIïŒGeminiïŒãã³ãŒãçæããã¡ã€ã«äœæãçŽæ¥å®è¡ã§ããŸãã
- **æ
åœ: 人é** - ãã®ã¢ã€ã³ã³ãä»ããŠããã¿ã¹ã¯ã¯ãéçºè
ã«ããæåã§ã®å®è¡ã倿ããŸãã¯æ¿èªãå¿
èŠã§ãã
### ãã§ãŒãº0: ãããžã§ã¯ãã®åæå
**ç®ç:** æ°ãããããžã§ã¯ãã®äœæ¥ãéå§ããããã®æºåãè¡ãã
- [x] **äžã¿ã¹ã¯0.1: ãããžã§ã¯ãã«ãŒããã£ã¬ã¯ããªã®äœæ**
- **æ
åœ:** 人é
- **å
容:** äœæ¥ãéå§ãããã£ã¬ã¯ããªã«ããããžã§ã¯ãã®ã«ãŒããšãªã `kids-playground-ai-api` ãã£ã¬ã¯ããªãäœæãããã®äžã«ç§»åããŠãã ããã
- **æç€º:** 以äžã®ã³ãã³ããå®è¡ããŠãã ããã
```bash
mkdir kids-playground-ai-api
cd kids-playground-ai-api
```
- [x] **äžã¿ã¹ã¯0.2: Git管çã®éå§ãšåæã³ããã**
- **æ
åœ:** 人é
- **å
容:** ãããžã§ã¯ãã®Git管çãéå§ãã`.gitignore`ãèšå®ããŠäžèŠãªãã¡ã€ã«ã管ç察象ããé€å€ããåæã³ããããè¡ããŸãã
- **æç€º:** ãããžã§ã¯ãã«ãŒããã£ã¬ã¯ããªã§ä»¥äžã®ã³ãã³ããå®è¡ããŠãã ããã
```bash
git init
# .gitignore ãã¡ã€ã«ãäœæãŸãã¯ç·šéããé©åãªå
容ãèšè¿°
# äŸ:
# echo "__pycache__\nvirtualenv/\.env" > .gitignore
git add .
git commit -m "Initial commit"
```
- [x] **äžã¿ã¹ã¯0.3: GitHubãªããžããªã®äœæãšé£æº**
- **æ
åœ:** 人é
- **å
容:** GitHubäžã«æ°ãããªããžããªãäœæããããŒã«ã«ãªããžããªãšé£æºãããŸãã
- **æç€º:**
1. GitHubã«ãã°ã€ã³ããæ°ãããªããžããªãäœæããŸãïŒãªããžããªå㯠`kids-playground-ai-api` ãªã©ïŒãREADMEã.gitignoreãã©ã€ã»ã³ã¹ã®è¿œå ã¯ã¹ãããããŠãã ããã
2. äœæããããªããžããªããŒãžã«è¡šç€ºãããæç€ºã«åŸããããŒã«ã«ãªããžããªããªã¢ãŒãã«ããã·ã¥ããŸãã
```bash
git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPOSITORY_NAME.git
git branch -M main
git push -u origin main
```
- [x] **äžã¿ã¹ã¯0.4: Hugging Faceã¢ã«ãŠã³ãã®ç»é²ãšSpacesã®æºå**
- **æ
åœ:** 人é
- **å
容:** Hugging Faceã¢ã«ãŠã³ããç»é²ããAIã¢ãã«ããããã€ããããã®Hugging Face SpaceãæºåããŸãã
- **æç€º:**
1. Hugging Faceã®ãŠã§ããµã€ã (huggingface.co) ã«ã¢ã¯ã»ã¹ããã¢ã«ãŠã³ããç»é²ããŸãã
2. ãã°ã€ã³åŸããSpacesãã»ã¯ã·ã§ã³ã«ç§»åãããCreate new Spaceããã¯ãªãã¯ããŸãã
3. Spaceåãã©ã€ã»ã³ã¹ãSDKïŒGradioãéžæïŒãå
¬é/éå
¬éèšå®ãªã©ãé©åã«èšå®ããSpaceãäœæããŸãã
- [x] **äžã¿ã¹ã¯0.5: ã©ã€ã»ã³ã¹ãã¡ã€ã«ã®äœæ**
- **æ
åœ:** AI
- **å
容:** ãããžã§ã¯ãã®ã©ã€ã»ã³ã¹ãã¡ã€ã«ã`LICENSE`ãšããååã§äœæããŸãã
- **æç€º:** ãããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã«`LICENSE`ãã¡ã€ã«ãäœæããé©åãªã©ã€ã»ã³ã¹ïŒäŸ: MIT LicenseïŒã®å
容ãèšè¿°ããŠãã ããã
### ãã§ãŒãº1: éçºç°å¢ã®ã»ããã¢ãã
**ç®ç:** ã³ãŒãã£ã³ã°ãéå§ããåã«ãå質ãæ
ä¿ããéçºãå¹çåããããã®åºç€ãæ§ç¯ããã
- [x] **äžã¿ã¹ã¯1.0: ããã¥ã¡ã³ãã®é
眮**
- **æ
åœ:** AI
- **å
容:** ãã®éçºã¬ã€ã (`ai_api_development_guide.md`) ã `docs/` ãã£ã¬ã¯ããªã«é
眮ããŸãã
- **æç€º:** 以äžã®ã³ãã³ããå®è¡ããŠãã ããã
```bash
cp /path/to/current/ai_api_development_guide.md docs/ai_api_development_guide.md
```
* *泚: `/path/to/current/ai_api_development_guide.md` ã¯ããã®ããã¥ã¡ã³ããçŸåšçœ®ãããŠãã絶察ãã¹ã«çœ®ãæããå¿
èŠããããŸãã*
- [x] **äžã¿ã¹ã¯1.1: ãããžã§ã¯ãæ§é ã®åæã»ããã¢ãã**
- **æ
åœ:** AI
- **å
容:** 以äžã®ãã£ã¬ã¯ããªãšãã¡ã€ã«ããããžã§ã¯ãã«ãŒãã«äœæããŸãã
- ãã£ã¬ã¯ããª: `src/ai_api/core`, `tests/core`, `docs`, `.github/workflows`
- ãã¡ã€ã«: `.gitignore`, `Dockerfile`, `pyproject.toml`, `requirements.txt`, `README.md`, `.github/workflows/ci.yml` (空ãã¡ã€ã«ãšããŠ)
- **æç€º:** 以äžã®ã³ãã³ããå®è¡ããŠããããžã§ã¯ãã®åæãã£ã¬ã¯ããªãšãã¡ã€ã«ãæºåããŠãã ããã
```bash
mkdir -p src/ai_api/core tests/core docs .github/workflows
touch .gitignore Dockerfile pyproject.toml requirements.txt README.md .github/workflows/ci.yml
```
- [x] **äžã¿ã¹ã¯1.2: å質管çããŒã«ã®èšå®**
- [x] **å°ã¿ã¹ã¯1.2.1: `pyproject.toml` ã®èšå®**
- **æ
åœ:** AI
- **å
容:** ã»ã¯ã·ã§ã³ `9.10` ã®èšèšã«åºã¥ããRuff, Mypy, Pytestã®èšå®ãèšè¿°ãã `pyproject.toml` ãã¡ã€ã«ãæŽæ°ããŸãã
- **æç€º:** `/home/jam/kids-playground-ai-api/pyproject.toml` ãæŽæ°ããŠãã ããã
- [x] **å°ã¿ã¹ã¯1.2.2: `pre-commit`ããã¯ã®èšå®ãšã€ã³ã¹ããŒã«**
- **æ
åœ:** AI
- **å
容:** `pre-commit`ããã¯ãèšå®ããGitã³ãããæã«èªåã§ã³ãŒããã§ãã¯ãèµ°ãããã«ããŸãã
- **æç€º:** `.pre-commit-config.yaml`ãäœæããã³ã³ããå
ã§`pre-commit install`ãå®è¡ããŠãã ããã
- [x] **äžã¿ã¹ã¯1.3: äŸåé¢ä¿ã®ç®¡ç**
- [x] **å°ã¿ã¹ã¯1.3.1: `requirements.txt` ã®èšå®**
- **æ
åœ:** AI
- **å
容:** ã©ã€ãã©ãªãèšè¿°ãã `requirements.txt` ãæŽæ°ããŸãã
- **æç€º:** `/home/jam/kidsPlayGround/requirements.txt` ãæŽæ°ããŠãã ããã
```
# AI App
gradio
transformers
torch
# Testing
pytest
requests
# Linting & Formatting
ruff
mypy
```
- [x] **å°ã¿ã¹ã¯1.3.2: Dockeréçºç°å¢ã®æ§ç¯ãšèµ·å**
- **æ
åœ:** 人é
- **å
容:** Docker Desktopãå©çšããŠããããžã§ã¯ãã®Dockeréçºç°å¢ãæ§ç¯ããèµ·åããŸããããã«ãããå¿
èŠãªäŸåé¢ä¿ãã³ã³ããå
ã«èªåçã«ã€ã³ã¹ããŒã«ãããŸãã
- **æç€º:**
1. Docker Desktopãã€ã³ã¹ããŒã«ãããèµ·åããŠããããšã確èªããŠãã ããã
2. ãããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã§ã以äžã®ã³ãã³ããå®è¡ããŠDockerã³ã³ããããã«ãããããã¯ã°ã©ãŠã³ãã§èµ·åããŸãã
```bash
docker-compose up --build -d
```
3. ã³ã³ãããæ£åžžã«èµ·åããããDjangoã¢ããªã±ãŒã·ã§ã³ã¯ `http://localhost:8000`ãAI API (Gradio) 㯠`http://localhost:7860` ã§ã¢ã¯ã»ã¹å¯èœã«ãªããŸãã
- [x] **äžã¿ã¹ã¯1.4: ç°å¢å€æ°èšå®ãã¡ã€ã«ã®æºå (`.env`, `.env.example`)**
- **æ
åœ:** AI
- **å
容:** ç°å¢å€æ°èšå®ãã¡ã€ã«ïŒ`.env`ïŒãšãã®ãã³ãã¬ãŒãïŒ`.env.example`ïŒãäœæããŸãã
- **æç€º:** ãããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã«`.env`ãã¡ã€ã«ãš`.env.example`ãã¡ã€ã«ãäœæããŠãã ããã
- [x] **äžã¿ã¹ã¯1.5: VSCodeãšDockerã³ã³ããã®é£æº (Dev Containers)**
- [x] **å°ã¿ã¹ã¯1.5.1: ãDev Containersãæ¡åŒµæ©èœã®ã€ã³ã¹ããŒã« (人é):** VSCodeã«`ms-vscode-remote.remote-containers`æ¡åŒµæ©èœãã€ã³ã¹ããŒã«ããã
- [x] **å°ã¿ã¹ã¯1.5.2: `devcontainer.json`èšå®ãã¡ã€ã«ã®äœæ (AI):** ãããžã§ã¯ãã«ãŒãã«`.devcontainer`ãã£ã¬ã¯ããªãšã`docker-compose.yml`ã®`api`ãµãŒãã¹ã«æ¥ç¶ããããã®`devcontainer.json`ãã¡ã€ã«ãäœæããã
- [x] **å°ã¿ã¹ã¯1.5.3: ã³ã³ããå
ã§ã®åãªãŒãã³ (人é):** VSCodeã®ã³ãã³ããã¬ãããããReopen in Containerããå®è¡ããVSCodeãã³ã³ããã«æ¥ç¶ãããç¶æ
ã§åèµ·åããããšã確èªããã
### ãã§ãŒãº2: CI/CDæ€èšŒçšãµã³ãã«ã¢ããªã±ãŒã·ã§ã³ã®äœæ
**ç®ç:** CI/CDãã€ãã©ã€ã³ãå
šäœãšããŠæ©èœããããšãæ€èšŒããããã®ãæãã·ã³ãã«ãªãHello WorldãçãªGradioã¢ããªã±ãŒã·ã§ã³ãäœæããã
- [x] **äžã¿ã¹ã¯2.1: Gradioãµã³ãã«ã³ãŒãã®å®è£
**
- [x] **å°ã¿ã¹ã¯2.1.1 (RED):** `main.py`ã®ãã¹ããäœæ
- **æ
åœ:** AI
- **å
容:** `tests/test_main.py`ãäœæãã`main.py`ã®`greet`颿°ãç¹å®ã®æååãè¿ãããšãæåŸ
ãããã¹ããèšè¿°ããŸãããã®æç¹ã§ã¯`main.py`ã`greet`颿°ãååšããªãããããã¹ãã¯å€±æããŸãã
- [x] **å°ã¿ã¹ã¯2.1.2 (GREEN):** `main.py`ã«ãµã³ãã«ãå®è£
- **æ
åœ:** AI
- **å
容:** `src/ai_api/main.py`ã«ãç°¡åãª`greet`颿°ãšããããåŒã³åºãGradioã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ãããã¹ãããã¹ãããŸãã
- [x] **å°ã¿ã¹ã¯2.1.3 (REFACTOR):** ãªãã¡ã¯ã¿ãªã³ã°
- **æ
åœ:** AI
- **å
容:** ã³ãŒããæŽçããå¯èªæ§ãé«ããŸãã
### ãã§ãŒãº3: CI/CDã®æ§ç¯ãšãããã€
**ç®ç:** ã³ãŒãã®å質ãèªåçã«æ€èšŒããHugging Face Spacesãžèªåçã«ãããã€ããä»çµã¿ãæ§ç¯ããã
- [x] **äžã¿ã¹ã¯3.1: CIã¯ãŒã¯ãããŒã®æ§ç¯ (GitHub Actions)**
- [x] **å°ã¿ã¹ã¯3.1.1 (RED):** CIèšå®ãã¡ã€ã«ã®éªšæ Œäœæ
- **æ
åœ:** AI
- **å
容:** `.github/workflows/ci.yml` ãäœæããŸããæåã¯ããªã¬ãŒã ããèšè¿°ããå
·äœçãªãžã§ãã¯ç©ºã«ããŠãããŸãããã®æç¹ã§ã¯äœãå®è¡ãããŸããã
- [x] **å°ã¿ã¹ã¯3.1.2 (GREEN):** CIãžã§ãã®å®è£
- **æ
åœ:** AI
- **å
容:** `ci.yml` ã«ãPythonã®ã»ããã¢ãããäŸåé¢ä¿ã®ã€ã³ã¹ããŒã«ã`ruff`ã«ããlintãã§ãã¯ã`mypy`ã«ããåãã§ãã¯ã`pytest`ã«ãããã¹ãå®è¡ã®ã¹ãããã远å ããŸãã
- **æç€º:** `/home/jam/kids-playground-ai-api/.github/workflows/ci.yml` ãæŽæ°ããŠãã ããã
- [x] **å°ã¿ã¹ã¯3.1.3 (REFACTOR):** ã¯ãŒã¯ãããŒã®æé©å
- **æ
åœ:** AI
- **å
容:** ãã£ãã·ã¥æ©æ§ãªã©ãå°å
¥ããCIã®å®è¡æéãççž®ããŸãã
- [x] **å°ã¿ã¹ã¯3.1.4: CIã®åäœç¢ºèª**
- **æ
åœ:** 人é
- **å
容:** ãã®å€æŽãGitHubã«ããã·ã¥ããGitHubã®ãActionsãã¿ãã§ã¯ãŒã¯ãããŒãæ£ããå®è¡ãããå
šãŠã®ãã§ãã¯ãæåããããšã確èªããŸãã
- [ ] **äžã¿ã¹ã¯3.2: CDã¯ãŒã¯ãããŒã®æ§ç¯ (GitHub Actions)**
- [ ] **å°ã¿ã¹ã¯3.2.1: Hugging Faceã¢ã¯ã»ã¹ããŒã¯ã³ã®æºå**
- **æ
åœ:** 人é
- **å
容:** Hugging Faceã®èšå®ããŒãžã§`write`æš©éãæã€ã¢ã¯ã»ã¹ããŒã¯ã³ãçºè¡ãããããGitHubãªããžããªã®Secretsã«`HF_TOKEN`ãšããŠç»é²ããŸãã
- [ ] **å°ã¿ã¹ã¯3.2.2 (RED):** ãããã€ãžã§ãã®éªšæ Œäœæ
- **æ
åœ:** AI
- **å
容:** `ci.yml`ã«ã`test`ãžã§ãã®æååŸã«`main`ãã©ã³ãã§ã®ã¿å®è¡ããã`deploy-to-hf-space`ãžã§ãã远å ããŸããæåã¯ç°¡åãª`echo`ã³ãã³ãã®ã¿ãèšè¿°ãããããã€ãå®è¡ãããªãç¶æ
ã«ããŸãã
- [ ] **å°ã¿ã¹ã¯3.2.3 (GREEN):** ãããã€ãžã§ãã®å®è£
- **æ
åœ:** AI
- **å
容:** `deploy-to-hf-space`ãžã§ãã«ã`hugging-face/push-to-hub`ã¢ã¯ã·ã§ã³ã远å ããSecretsã«ç»é²ãã`HF_TOKEN`ã䜿ã£ãŠHugging Face Spacesã«ã³ãŒããããã·ã¥ããããã«å®è£
ããŸãã
- [ ] **å°ã¿ã¹ã¯3.2.4: CDã®åäœç¢ºèª**
- **æ
åœ:** 人é
- **å
容:** CI/CDãæåããã³ãããã`main`ãã©ã³ãã«ããŒãžããGitHubã®ãActionsãã¿ãã§ãããã€ãžã§ããæåããããšã確èªããŸãããã®åŸãHugging Face Spaceã®å
¬éURLã«ã¢ã¯ã»ã¹ããã¢ããªã±ãŒã·ã§ã³ãæ£ãããããã€ãããŠããããšã確èªããŸãã
### ãã§ãŒãº4: AIã¢ããªã±ãŒã·ã§ã³ã®TDD (ã³ã¢ããžã㯠â API)
**ç®ç:** ã¯ãªãŒã³ã¢ãŒããã¯ãã£ã®ååã«åŸããå
åŽã®ããžãã¹ããžãã¯ããå€åŽã®APIãžãšå®è£
ãé²ããã
- [ ] **äžã¿ã¹ã¯4.1: AIã³ã¢ããžã㯠`Summarizer` ã®å®è£
**
- [ ] **å°ã¿ã¹ã¯4.1.1 (RED):** `Summarizer`ã¯ã©ã¹ã®ãã¹ãäœæ
- **æ
åœ:** AI
- **å
容:** `tests/core/test_inference.py` ãäœæããã`from ai_api.core.inference import Summarizer` ãæåããããšãããã¹ãããŸãããã®ãã¹ãã¯ããã¡ã€ã«ãã¯ã©ã¹ãååšããªããã倱æããŸãã
- [ ] **å°ã¿ã¹ã¯4.1.2 (GREEN):** `Summarizer`ã¯ã©ã¹ã®éªšæ Œäœæ
- **æ
åœ:** AI
- **å
容:** `src/ai_api/core/inference.py` ãšã空ã®`Summarizer`ã¯ã©ã¹ãäœæãããã¹ãããã¹ãããŸãã
- [ ] **å°ã¿ã¹ã¯4.1.3 (REFACTOR):** ãªãã¡ã¯ã¿ãªã³ã°
- **æ
åœ:** AI
- **å
容:** ãã®æç¹ã§ã¯ç¹ã«ãªããã³ãããã®åºåããšããŸãã
- [ ] **äžã¿ã¹ã¯4.2: AIèšå®ã¯ã©ã¹ `Config` ã®å®è£
ãšæ³šå
¥**
- [ ] **å°ã¿ã¹ã¯4.2.1 (RED):** `Summarizer`ãèšå®ãªããžã§ã¯ããåãåããã¹ãäœæ
- **æ
åœ:** AI
- **å
容:** `tests/core/test_inference.py`ã«è¿œèšããŸãã
- **å
容:** `Summarizer`ãã³ã³ã¹ãã©ã¯ã¿ã§èšå®ãªããžã§ã¯ãïŒã¢ãã«åãªã©ïŒãåãåãããšãæåŸ
ãããã¹ãã`tests/core/test_inference.py`ã«è¿œèšããŸãã
- [ ] **å°ã¿ã¹ã¯4.2.2 (GREEN):** èšå®ã¯ã©ã¹ã®äœæãšã³ã³ã¹ãã©ã¯ã¿ä¿®æ£
- **æ
åœ:** AI
- **å
容:** `src/ai_api/config.py`ã«èšèšéãã®èšå®ã¯ã©ã¹ïŒ`ModelConfig`ãªã©ïŒãäœæããŸãã`Summarizer`ã®`__init__`ãä¿®æ£ããèšå®ãªããžã§ã¯ããåãåãããã«ããŸãã
- [ ] **å°ã¿ã¹ã¯4.2.3 (REFACTOR):** ãªãã¡ã¯ã¿ãªã³ã°
- **æ
åœ:** AI
- **å
容:** ã³ãŒãã®å¯èªæ§ãåäžãããŸãã **ãã®æç¹ã§ãAIã¢ãã«ãåãæ¿ããããã®åºæ¬çãªä»çµã¿ïŒèšå®å€ãå€éšããäžããïŒã宿ããŸãã**
- [ ] **äžã¿ã¹ã¯4.3: èŠçŽæ©èœ `summarize` ã¡ãœããã®å®è£
**
- [ ] **å°ã¿ã¹ã¯4.3.1 (RED):** `summarize`ã¡ãœããã®ãŠããããã¹ãäœæ
- **æ
åœ:** AI
- **å
容:** `unittest.mock.patch`ã䜿ãã`transformers.pipeline`ãã¢ãã¯ïŒåœç©ã«å·®ãæ¿ãïŒããŸããã`summarize`ã¡ãœãããåŒã¶ãšãå
éšã§`pipeline`ãç¹å®ã®åŒæ°ã§åŒã°ããã¢ãã¯ã®è¿ãå€ããã®ãŸãŸè¿ãããããšãããã¹ãããŸããããã«ãããéãã¢ãã«ãããŒãããã«ããžãã¯ã ããé«éã«ãã¹ãã§ããŸãã
- [ ] **å°ã¿ã¹ã¯4.3.2 (GREEN):** `summarize`ã¡ãœããã®å®è£
- **æ
åœ:** AI
- **å
容:** `Summarizer`ã¯ã©ã¹ã«`summarize`ã¡ãœãããå®è£
ããå
éšã§`transformers.pipeline`ãåŒã³åºããŠèŠçŽãå®è¡ããããã«ããŸãã
- [ ] **å°ã¿ã¹ã¯4.3.3 (REFACTOR):** ãªãã¡ã¯ã¿ãªã³ã°
- **æ
åœ:** AI
- **å
容:** ãšã©ãŒãã³ããªã³ã°ãªã©ã远å ããã³ãŒããæŽçããŸãã
- [ ] **äžã¿ã¹ã¯4.4: APIãšã³ããªãŒãã€ã³ã `main.py` ã®å®è£
**
- [ ] **å°ã¿ã¹ã¯4.4.1 (RED):** APIã®ã€ã³ãã°ã¬ãŒã·ã§ã³ãã¹ãäœæ
- **æ
åœ:** AI
- **å
容:** `tests/test_api.py`ãäœæããŸãããã¹ãå
ã§Gradioã¢ããªãå¥ã¹ã¬ããã§èµ·åãã`requests.post`ã§`/api/predict/`ã«ãªã¯ãšã¹ããéä¿¡ããŠãæåŸ
ããå¿çãåŸãããªãïŒãµãŒããŒããªãããïŒããšã確èªããŸãã
- [ ] **å°ã¿ã¹ã¯4.4.2 (GREEN):** `main.py`ã®å®è£
- **æ
åœ:** AI
- **å
容:** `src/ai_api/main.py`ãäœæããŸãã`Summarizer`ãšèšå®ã¯ã©ã¹ãã€ã³ã¹ã¿ã³ã¹åããDIïŒäŸåæ§ã®æ³šå
¥ïŒããŠGradioã®`Interface`ãå®çŸ©ã»èµ·åããŸãã
- [ ] **å°ã¿ã¹ã¯4.4.3 (REFACTOR):** ãªãã¡ã¯ã¿ãªã³ã°
- **æ
åœ:** AI
- **å
容:** ã³ãŒããæŽçããŸãã
- [ ] **å°ã¿ã¹ã¯4.4.4: æåã§ã®åäœç¢ºèª**
- **æ
åœ:** 人é
- **å
容:** `python src/ai_api/main.py` ãå®è¡ãããã©ãŠã¶ã§è¡šç€ºãããGradioã®UIã«ããã¹ããå
¥åããŠãèŠçŽæ©èœãåäœã§æ£ããåäœããããšã確èªããŸãã
### ãã§ãŒãº5: Djangoãžã®çµã¿èŸŒã¿
**ç®ç:** ç¬ç«ããŠåäœããAIã¢ããªã±ãŒã·ã§ã³ããDjangoããAPIçµç±ã§å®å
šã«åŒã³åºãã
- [ ] **äžã¿ã¹ã¯5.1: DjangoåŽã®APIã¯ã©ã€ã¢ã³ãå®è£
**
- [ ] **å°ã¿ã¹ã¯5.1.1 (RED):** APIã¯ã©ã€ã¢ã³ãã®ãã¹ãäœæ
- **æ
åœ:** AI
- **å
容:** `myapp/tests/test_clients.py`ãäœæããŸãã`requests.post`ãã¢ãã¯åãããŠããç¶æ
ã§APIã¯ã©ã€ã¢ã³ã颿°ãåŒã³åºããæåæã»ã¿ã€ã ã¢ãŠãæã»ãµãŒããŒãšã©ãŒæã®æåããã¹ãããŸãã
- [ ] **å°ã¿ã¹ã¯5.1.2 (GREEN):** APIã¯ã©ã€ã¢ã³ãã®å®è£
- **æ
åœ:** AI
- **å
容:** `myapp/clients/ai_summary_client.py`ãäœæãã`requests`ã䜿ã£ãŠå€éšAPIãåŒã³åºã颿°ãå®è£
ããŸãã
- [ ] **å°ã¿ã¹ã¯5.1.3 (REFACTOR):** ãªãã¡ã¯ã¿ãªã³ã°
- **æ
åœ:** AI
- **å
容:** èšå®ã`settings.py`ããèªã¿èŸŒãããã«ãããªã©ãã³ãŒããæŽçããŸãã
- [ ] **äžã¿ã¹ã¯5.2: Django Viewã®å®è£
**
- [ ] **å°ã¿ã¹ã¯5.2.1 (RED):** Viewã®URLãã¹ãäœæ
- **æ
åœ:** AI
- **å
容:** `myapp/tests/test_views.py`ã«ã`/summarize/playground/{id}/`ãžã®GETãªã¯ãšã¹ãã404ãè¿ããã¹ããæžããŸãã
- [ ] **å°ã¿ã¹ã¯5.2.2 (GREEN):** URLãšViewã®éªšæ Œäœæ
- **æ
åœ:** AI
- **å
容:** `myapp/urls.py`ãš`myapp/views/summary_views.py`ãäœæã»ç·šéãããã¹ãããã¹ãããŸãã
- [ ] **å°ã¿ã¹ã¯5.2.3 (RED):** Viewãšã¯ã©ã€ã¢ã³ãã®é£æºãã¹ãäœæ
- **æ
åœ:** AI
- **å
容:** `unittest.mock.patch`ã§APIã¯ã©ã€ã¢ã³ããã¢ãã¯åãããViewãåŒã³åºããšãå
éšã§APIã¯ã©ã€ã¢ã³ããç¹å®ã®åŒæ°ã§åŒã°ããããšãããã¹ãããŸãã
- [ ] **å°ã¿ã¹ã¯5.2.4 (GREEN):** Viewããžãã¯ã®å®è£
- **æ
åœ:** AI
- **å
容:** Viewå
ã§å£ã³ãã®ååŸã»æ€èšŒããžãã¯ãããã³APIã¯ã©ã€ã¢ã³ãã®åŒã³åºããå®è£
ããŸãã
- [ ] **å°ã¿ã¹ã¯5.2.5 (REFACTOR):** ãªãã¡ã¯ã¿ãªã³ã°
- **æ
åœ:** AI
- **å
容:** ã³ãŒããæŽçããŸãã
- [x] **äžã¿ã¹ã¯5.3: çµ±åãã¹ã**
- [x] **å°ã¿ã¹ã¯5.3.1: æåã§ã®æçµç¢ºèª**
- **æ
åœ:** 人é
- **å
容:** DjangoãµãŒããŒãšAIã¢ããªïŒGradioïŒãäž¡æ¹ããŒã«ã«ã§èµ·åãããã©ãŠã¶ããæåã®èŠçŽãã¿ã³ãã¯ãªãã¯ããŠãå
šäœã®æµããæ£ããåäœãããã確èªããŸãã
```
|