diff --git a/sam/docs/INDEX.md b/sam/docs/INDEX.md index 7152079..16ab051 100644 --- a/sam/docs/INDEX.md +++ b/sam/docs/INDEX.md @@ -168,6 +168,9 @@ docs/ | [table-design-guide.md](guides/table-design-guide.md) | 테이블 설계 가이드 (비전문가용, options JSON 패턴) | 테이블 구조 이해 시 | | [item-master-guide.md](guides/item-master-guide.md) | 품목기준관리 페이지-섹션-필드 구조 | 품목 UI 구현 시 | | [item-master-items-api.md](guides/item-master-items-api.md) | ItemMaster & Items API 문서 | 품목 API 연동 시 | +| [ai-management.md](guides/ai-management.md) | AI 관리 종합 가이드 (아키텍처, 버전 이력, 온보딩) | AI 관련 작업 시 | +| [ai-model-update-workflow.md](guides/ai-model-update-workflow.md) | AI 모델 업데이트 표준 절차 (7단계) | AI 모델 변경 시 | +| [ai-config-settings.md](guides/ai-config-settings.md) | AI 설정 기술문서 (DB 구조, 메서드) | AI 설정 구현 시 | --- diff --git a/sam/docs/changes/20260303_gemini_model_upgrade.md b/sam/docs/changes/20260303_gemini_model_upgrade.md new file mode 100644 index 0000000..e3806fc --- /dev/null +++ b/sam/docs/changes/20260303_gemini_model_upgrade.md @@ -0,0 +1,119 @@ +# Gemini 모델 업그레이드: 2.0-flash → 2.5-flash + +**날짜:** 2026-03-03 +**작업자:** Claude Code + +--- + +## 변경 개요 + +Google이 2026년 6월 1일부로 Gemini 2.0 Flash 모델 서비스를 종료한다는 통보를 받아, SAM 시스템 전체의 Gemini 모델을 `gemini-2.0-flash` → `gemini-2.5-flash`로 마이그레이션했다. + +--- + +## 변경 사유 + +- Google의 공식 메일 통보: Gemini 2.0 Flash / 2.0 Flash-Lite → 2026-06-01 강제 종료 +- 마이그레이션 경로: `gemini-2.0-flash` → `gemini-2.5-flash` +- API 키, Base URL 변경 없음 (모델명만 변경) + +--- + +## 수정된 파일 + +### API 프로젝트 (`/home/aweso/sam/api`) + +| 파일 | 변경 내용 | +|------|----------| +| `.env` | `GEMINI_MODEL=gemini-2.0-flash` → `gemini-2.5-flash` | +| `config/services.php` | fallback 기본값 `gemini-2.0-flash` → `gemini-2.5-flash` | +| `app/Services/AiReportService.php` | fallback 기본값 변경 | + +### MNG 프로젝트 (`/home/aweso/sam/mng`) + +| 파일 | 변경 내용 | +|------|----------| +| `.env` | `GEMINI_MODEL=gemini-2.0-flash` → `gemini-2.5-flash` | +| `config/services.php` | fallback 기본값 변경 | +| `app/Models/System/AiConfig.php` | `DEFAULT_MODELS['gemini']` 상수 + `getActiveGemini()` fallback 변경 | +| `app/Services/NotionService.php` | fallback 기본값 변경 | +| `resources/views/system/ai-config/index.blade.php` | UI placeholder, 기본값, JS defaultModels 변경 | +| `resources/views/google-cloud/ai-guide/index.blade.php` | 서비스 현황 테이블 모델명 7곳 변경 | +| `resources/views/academy/env-management.blade.php` | 환경변수 예시 테이블 변경 | + +### 문서 (`/home/aweso/sam/docs`) + +| 파일 | 변경 내용 | +|------|----------| +| `guides/ai-config-settings.md` | 기본 모델명 업데이트, 최종 업데이트 날짜 변경 | +| `guides/ai-management.md` | **신규** — AI 관리 종합 가이드 (아키텍처, 버전 이력, 온보딩) | +| `guides/ai-model-update-workflow.md` | **신규** — 모델 업데이트 표준 절차 (7단계 워크플로우) | +| `changes/20260303_gemini_model_upgrade.md` | **신규** — 이 변경 이력 문서 | + +### 수정하지 않은 파일 (의도적) + +| 파일 | 이유 | +|------|------| +| `api/database/migrations/2026_01_27_*.php` | 이미 실행된 마이그레이션 — 변경 시 DB 무결성 문제 | +| `api/database/migrations/2026_02_07_*.php` | 동일 | +| `api/database/migrations/2026_02_09_*.php` | 동일 | +| `mng/views/google-cloud/cloud-api-pricing/index.blade.php` | `2.0 → 2.5` 마이그레이션 안내 UI — 이전 모델명이 의도적 잔존 | + +--- + +## 서버 .env 수정 필요 (배포 후) + +| 환경 | 파일 | 변수 | 담당 | +|------|------|------|------| +| 개발서버 | `/home/webservice/api/.env` | `GEMINI_MODEL=gemini-2.5-flash` | SSH 접속 수정 | +| 개발서버 | `/home/webservice/mng/.env` | `GEMINI_MODEL=gemini-2.5-flash` | SSH 접속 수정 | +| 운영서버 | `/home/webservice/api/.env` | `GEMINI_MODEL=gemini-2.5-flash` | 개발팀장 직접 | +| 운영서버 | `/home/webservice/mng/.env` | `GEMINI_MODEL=gemini-2.5-flash` | 개발팀장 직접 | + +수정 후 반드시 실행: +```bash +php artisan config:clear +``` + +--- + +## DB 단가 설정 필요 + +MNG `/system/ai-token-usage` → 단가 설정에서: +- 기존 `gemini-2.0-flash` 단가 → 비활성화 +- 신규 `gemini-2.5-flash` 단가 추가: + - `input_price_per_million`: 0.15 + - `output_price_per_million`: 0.60 + - `exchange_rate`: 현재 환율 + +--- + +## 테스트 체크리스트 + +- [x] 로컬 .env 수정 완료 +- [x] 코드 fallback 전체 변경 완료 +- [ ] 로컬 연결 테스트 (MNG `/system/ai-config`) +- [ ] 개발서버 .env 수정 + config:clear +- [ ] 개발서버 연결 테스트 +- [ ] 운영서버 .env 수정 + config:clear +- [ ] DB 단가 설정 (gemini-2.5-flash) +- [ ] 토큰 사용량 로그 확인 (새 모델명) + +--- + +## 롤백 절차 + +문제 발생 시 `.env`만 되돌리면 즉시 복구: +```bash +# 모든 환경의 .env에서 +GEMINI_MODEL=gemini-2.0-flash +php artisan config:clear +``` + +--- + +## 관련 문서 + +- [AI 관리 종합 가이드](../guides/ai-management.md) +- [모델 업데이트 워크플로우](../guides/ai-model-update-workflow.md) +- [AI 설정 기술문서](../guides/ai-config-settings.md) diff --git a/sam/docs/guides/ai-config-settings.md b/sam/docs/guides/ai-config-settings.md new file mode 100644 index 0000000..af31d72 --- /dev/null +++ b/sam/docs/guides/ai-config-settings.md @@ -0,0 +1,325 @@ +# AI 및 스토리지 설정 기술문서 + +> 최종 업데이트: 2026-03-03 + +## 개요 + +SAM MNG 시스템의 AI API 및 클라우드 스토리지(GCS) 설정을 관리하는 기능입니다. +관리자 UI에서 설정하거나, `.env` 환경변수로 설정할 수 있습니다. + +**접근 경로**: 시스템 관리 > AI 설정 (`/system/ai-config`) + +--- + +## 지원 Provider + +### AI Provider +| Provider | 용도 | 기본 모델 | +|----------|------|----------| +| `gemini` | Google Gemini (명함 OCR, AI 어시스턴트) | gemini-2.5-flash | +| `claude` | Anthropic Claude | claude-sonnet-4-20250514 | +| `openai` | OpenAI GPT | gpt-4o | + +### Storage Provider +| Provider | 용도 | +|----------|------| +| `gcs` | Google Cloud Storage (음성 녹음 백업) | + +--- + +## 데이터베이스 구조 + +### 테이블: `ai_configs` + +```sql +CREATE TABLE ai_configs ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(50) NOT NULL, -- 설정 이름 (예: "Production Gemini") + provider VARCHAR(20) NOT NULL, -- gemini, claude, openai, gcs + api_key VARCHAR(255) NOT NULL, -- API 키 (GCS는 'gcs_service_account') + model VARCHAR(100) NOT NULL, -- 모델명 (GCS는 '-') + base_url VARCHAR(255) NULL, -- 커스텀 Base URL + description TEXT NULL, -- 설명 + is_active BOOLEAN DEFAULT FALSE, -- 활성화 여부 (provider당 1개만) + options JSON NULL, -- 추가 옵션 (아래 참조) + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP NULL -- Soft Delete +); +``` + +### options JSON 구조 + +**AI Provider (Gemini Vertex AI)**: +```json +{ + "auth_type": "vertex_ai", + "project_id": "my-gcp-project", + "region": "us-central1", + "service_account_path": "/var/www/sales/apikey/google_service_account.json" +} +``` + +**AI Provider (API Key)**: +```json +{ + "auth_type": "api_key" +} +``` + +**GCS Provider**: +```json +{ + "bucket_name": "my-bucket-name", + "service_account_path": "/var/www/sales/apikey/google_service_account.json", + "service_account_json": { ... } // 또는 JSON 직접 입력 +} +``` + +--- + +## 설정 우선순위 + +### GCS 설정 우선순위 + +``` +1. DB 설정 (ai_configs 테이블의 활성화된 gcs provider) + ↓ 없으면 +2. 환경변수 (.env의 GCS_BUCKET_NAME, GCS_SERVICE_ACCOUNT_PATH) + ↓ 없으면 +3. 레거시 파일 (/sales/apikey/gcs_config.txt, google_service_account.json) +``` + +### AI 설정 우선순위 + +``` +1. DB 설정 (ai_configs 테이블의 활성화된 provider) + ↓ 없으면 +2. 환경변수 (.env의 GEMINI_API_KEY 등) + ↓ 없으면 +3. 레거시 파일 +``` + +--- + +## 환경변수 설정 (.env) + +### GCS 설정 +```env +# Google Cloud Storage (음성 녹음 백업) +GCS_BUCKET_NAME=your-bucket-name +GCS_SERVICE_ACCOUNT_PATH=/var/www/sales/apikey/google_service_account.json +GCS_USE_DB_CONFIG=true # false면 DB 설정 무시, .env만 사용 +``` + +### AI 설정 (참고) +```env +# Google Gemini API +GEMINI_API_KEY=your-api-key +GEMINI_PROJECT_ID=your-project-id +``` + +--- + +## 관련 파일 목록 + +### 모델 +| 파일 | 설명 | +|------|------| +| `app/Models/System/AiConfig.php` | AI 설정 Eloquent 모델 | + +### 컨트롤러 +| 파일 | 설명 | +|------|------| +| `app/Http/Controllers/System/AiConfigController.php` | CRUD + 연결 테스트 | + +### 서비스 +| 파일 | 설명 | +|------|------| +| `app/Services/GoogleCloudStorageService.php` | GCS 업로드/다운로드/삭제 | +| `app/Services/GeminiService.php` | Gemini API 호출 (명함 OCR 등) | + +### 설정 +| 파일 | 설명 | +|------|------| +| `config/gcs.php` | GCS 환경변수 설정 | + +### 뷰 +| 파일 | 설명 | +|------|------| +| `resources/views/system/ai-config/index.blade.php` | AI 설정 관리 페이지 | + +### 라우트 +```php +// routes/web.php +Route::prefix('system')->name('system.')->group(function () { + Route::resource('ai-config', AiConfigController::class)->except(['show', 'create', 'edit']); + Route::post('ai-config/{id}/toggle', [AiConfigController::class, 'toggle'])->name('ai-config.toggle'); + Route::post('ai-config/test', [AiConfigController::class, 'test'])->name('ai-config.test'); + Route::post('ai-config/test-gcs', [AiConfigController::class, 'testGcs'])->name('ai-config.test-gcs'); +}); +``` + +--- + +## 주요 메서드 + +### AiConfig 모델 + +```php +// Provider별 활성 설정 조회 +AiConfig::getActiveGemini(); // ?AiConfig +AiConfig::getActiveClaude(); // ?AiConfig +AiConfig::getActiveGcs(); // ?AiConfig +AiConfig::getActive('openai'); // ?AiConfig + +// GCS 전용 메서드 +$config->getBucketName(); // ?string +$config->getServiceAccountJson(); // ?array +$config->getServiceAccountPath(); // ?string +$config->isGcs(); // bool + +// Vertex AI 전용 메서드 +$config->isVertexAi(); // bool +$config->getProjectId(); // ?string +$config->getRegion(); // string (기본: us-central1) +``` + +### GoogleCloudStorageService + +```php +$gcs = new GoogleCloudStorageService(); + +// 사용 가능 여부 +$gcs->isAvailable(); // bool + +// 설정 소스 확인 +$gcs->getConfigSource(); // 'db' | 'env' | 'legacy' | 'none' + +// 파일 업로드 +$gcsUri = $gcs->upload($localPath, $objectName); // 'gs://bucket/object' | null + +// 서명된 다운로드 URL (60분 유효) +$url = $gcs->getSignedUrl($objectName, 60); // string | null + +// 파일 삭제 +$gcs->delete($objectName); // bool +``` + +--- + +## UI 구조 + +### 탭 구성 +- **AI 설정 탭**: Gemini, Claude, OpenAI 설정 관리 +- **스토리지 설정 탭**: GCS 설정 관리 + +### 기능 +- 설정 추가/수정/삭제 +- 활성화/비활성화 토글 (provider당 1개만 활성화) +- 연결 테스트 + +--- + +## 사용 예시 + +### GCS 업로드 (ConsultationController) + +```php +use App\Services\GoogleCloudStorageService; + +public function uploadAudio(Request $request) +{ + // 파일 저장 + $path = $file->store("tenant/consultations/{$tenantId}"); + $fullPath = storage_path('app/' . $path); + + // 10MB 이상이면 GCS에도 업로드 + if ($file->getSize() > 10 * 1024 * 1024) { + $gcs = new GoogleCloudStorageService(); + if ($gcs->isAvailable()) { + $gcsUri = $gcs->upload($fullPath, "consultations/{$tenantId}/" . basename($path)); + } + } +} +``` + +### 명함 OCR (GeminiService) + +```php +use App\Services\GeminiService; + +$gemini = new GeminiService(); +$result = $gemini->extractBusinessCard($imagePath); +``` + +--- + +## 배포 가이드 + +### 서버 최초 설정 + +1. `.env` 파일에 GCS 설정 추가: + ```env + GCS_BUCKET_NAME=production-bucket + GCS_SERVICE_ACCOUNT_PATH=/var/www/sales/apikey/google_service_account.json + ``` + +2. 서비스 계정 JSON 파일 배치: + ``` + /var/www/sales/apikey/google_service_account.json + ``` + +3. 설정 캐시 갱신: + ```bash + docker exec sam-mng-1 php artisan config:cache + ``` + +### 이후 배포 +- 코드 push만으로 동작 (설정 변경 불필요) +- UI에서 오버라이드하고 싶을 때만 DB 설정 사용 + +--- + +## 트러블슈팅 + +### GCS 업로드 실패 + +1. **설정 확인**: + ```php + $gcs = new GoogleCloudStorageService(); + dd($gcs->isAvailable(), $gcs->getConfigSource(), $gcs->getBucketName()); + ``` + +2. **로그 확인**: + ```bash + docker exec sam-mng-1 tail -f storage/logs/laravel.log | grep GCS + ``` + +3. **일반적인 원인**: + - 서비스 계정 파일 경로 오류 + - 서비스 계정에 Storage 권한 없음 + - 버킷 이름 오타 + +### AI API 연결 실패 + +1. **API 키 확인**: UI에서 "테스트" 버튼 클릭 +2. **모델명 확인**: provider별 지원 모델 확인 +3. **할당량 확인**: Google Cloud Console에서 API 할당량 확인 + +--- + +## 레거시 파일 위치 (참고) + +Docker 컨테이너 내부 경로: +``` +/var/www/sales/apikey/ +├── gcs_config.txt # bucket_name=xxx +├── google_service_account.json # GCP 서비스 계정 키 +└── gemini_api_key.txt # Gemini API 키 (레거시) +``` + +호스트 경로 (mng 기준): +``` +../sales/apikey/ +``` diff --git a/sam/docs/guides/ai-management.md b/sam/docs/guides/ai-management.md new file mode 100644 index 0000000..7da951d --- /dev/null +++ b/sam/docs/guides/ai-management.md @@ -0,0 +1,291 @@ +# SAM AI 관리 종합 가이드 + +> **작성일**: 2026-03-03 +> **상태**: 확정 +> **대상 독자**: SAM 프로젝트에 투입되는 모든 개발자 + +--- + +## 1. 개요 + +### 1.1 목적 + +SAM 시스템에서 사용하는 AI 서비스(Google Gemini, Anthropic Claude, OpenAI)의 **설정 구조, 호출 흐름, 모델 관리, 비용 추적**을 한눈에 파악할 수 있는 종합 가이드다. + +### 1.2 현재 상태 (2026-03-03) + +| Provider | 모델 | 용도 | 상태 | +|----------|------|------|------| +| **Google Gemini** | `gemini-2.5-flash` | 명함 OCR, 사업자등록증 OCR, 재무 리포트, 회의 요약, 동영상 스크립트 | ✅ 운영 중 | +| Anthropic Claude | `claude-sonnet-4-20250514` | AI 재무 분석 (예비) | 🟡 코드 준비 | +| OpenAI | `gpt-4o` | 범용 AI (예비) | 🟡 코드 준비 | +| Google Cloud STT | Chirp 2 | 음성 녹음 → 텍스트 변환 | ✅ 운영 중 | +| Google Cloud Storage | Standard | 음성 파일 백업 | ✅ 운영 중 | + +--- + +## 2. 아키텍처 + +### 2.1 설정 흐름도 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ .env 파일 (환경별 4곳) │ +│ ┌───────────────────────────────────────────┐ │ +│ │ GEMINI_API_KEY=AIzaSy... │ │ +│ │ GEMINI_MODEL=gemini-2.5-flash │ ← ① 핵심 │ +│ │ GEMINI_BASE_URL=https://...googleapis... │ │ +│ └───────────────────────────────────────────┘ │ +└────────────────────────┬────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ config/services.php │ +│ ┌───────────────────────────────────────────┐ │ +│ │ 'gemini' => [ │ │ +│ │ 'model' => env('GEMINI_MODEL', │ │ +│ │ 'gemini-2.5-flash'), │ ← ② fallback│ +│ │ ] │ │ +│ └───────────────────────────────────────────┘ │ +└────────────────────────┬────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ AiConfig::getActiveGemini() │ +│ ┌───────────────────────────────────────────┐ │ +│ │ config('services.gemini.model', │ │ +│ │ 'gemini-2.5-flash') │ ← ③ fallback│ +│ └───────────────────────────────────────────┘ │ +└────────────────────────┬────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ 서비스 클래스 (실제 API 호출) │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ BusinessCardOcrService → AiConfig::getActiveGemini│ │ +│ │ TradingPartnerOcrService → AiConfig::getActiveGemini│ │ +│ │ AiReportService (API) → config('services.gemini')│ │ +│ │ GeminiScriptService → AiConfig::getActiveGemini│ │ +│ │ NotionService → AiConfig::getActiveGemini│ │ +│ └─────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +> **핵심**: `.env`의 `GEMINI_MODEL` 값만 바꾸면 전체 서비스가 새 모델을 사용한다. + +### 2.2 프로젝트별 역할 + +| 프로젝트 | AI 관련 역할 | +|----------|-------------| +| **MNG** | 명함 OCR, 사업자등록증 OCR, 동영상 스크립트, AI 설정 관리 UI, 토큰 사용량 조회 | +| **API** | 재무 AI 리포트 생성, 토큰 사용량 저장, AI 가격 설정 | +| **React** | AI 기능 없음 (Google Maps만 사용) | + +--- + +## 3. 환경변수 설정 + +### 3.1 Gemini AI 설정 + +```env +# ─── Google Gemini AI ─── +GEMINI_API_KEY=AIzaSy... # Google AI Studio에서 발급 +GEMINI_MODEL=gemini-2.5-flash # 사용할 모델명 +GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta +GEMINI_PROJECT_ID=codebridge-chatbot # GCP 프로젝트 ID +``` + +### 3.2 환경별 .env 위치 + +| 환경 | API 경로 | MNG 경로 | +|------|---------|---------| +| 로컬 (Docker) | `/home/aweso/sam/api/.env` | `/home/aweso/sam/mng/.env` | +| 개발서버 | `/home/webservice/api/.env` | `/home/webservice/mng/.env` | +| 운영서버 | `/home/webservice/api/.env` | `/home/webservice/mng/.env` | + +> API와 MNG는 같은 `GEMINI_MODEL` 값을 사용해야 한다. + +--- + +## 4. 서비스별 AI 호출 매핑 + +### 4.1 MNG 프로젝트 + +| 서비스 | 파일 | 용도 | 설정 소스 | +|--------|------|------|----------| +| 명함 OCR | `app/Services/BusinessCardOcrService.php` | 명함 이미지 → 연락처 정보 추출 | `AiConfig::getActiveGemini()` | +| 사업자등록증 OCR | `app/Services/TradingPartnerOcrService.php` | 사업자등록증 → 거래처 정보 추출 | `AiConfig::getActiveGemini()` | +| 동영상 스크립트 | `app/Services/Video/GeminiScriptService.php` | 영상 자막/스크립트 생성 | `AiConfig::getActiveGemini()` | +| Notion 연동 | `app/Services/NotionService.php` | Notion 콘텐츠 AI 분석 | `AiConfig::getActiveGemini()` | + +### 4.2 API 프로젝트 + +| 서비스 | 파일 | 용도 | 설정 소스 | +|--------|------|------|----------| +| 재무 AI 리포트 | `app/Services/AiReportService.php` | 지출/매출/매입 데이터 AI 분석 | `config('services.gemini')` | + +### 4.3 공통 유틸 + +| 파일 | 역할 | +|------|------| +| `mng/app/Helpers/AiTokenHelper.php` | 토큰 사용량 저장 (Gemini, Claude, GCS, STT) | +| `mng/app/Models/System/AiConfig.php` | AI 설정 모델 (Provider별 활성 설정 조회) | +| `mng/app/Models/System/AiPricingConfig.php` | 토큰 단가 설정 (비용 계산) | +| `mng/app/Models/System/AiTokenUsage.php` | 토큰 사용 이력 | + +--- + +## 5. 관리 화면 + +### 5.1 AI 설정 관리 + +- **URL**: `/system/ai-config` +- **기능**: Provider별 API 키, 모델명, Base URL 관리 / 연결 테스트 / 활성화 토글 +- **컨트롤러**: `app/Http/Controllers/System/AiConfigController.php` + +### 5.2 AI 토큰 사용량 + +- **URL**: `/system/ai-token-usage` +- **기능**: 일별/메뉴별 토큰 사용량 조회 / 비용(USD, KRW) 통계 / 단가 설정 +- **컨트롤러**: `app/Http/Controllers/System/AiTokenUsageController.php` + +### 5.3 Google Cloud AI 가이드 + +- **URL**: `/google-cloud/ai-guide` +- **기능**: SAM에서 사용하는 Google AI 서비스 전체 현황 / 아키텍처 다이어그램 + +--- + +## 6. 모델 변경 이력 (버전 관리) + +| 날짜 | 변경 내용 | 이유 | 영향 범위 | +|------|----------|------|----------| +| 2026-01-27 | 최초 설정: `gemini-2.0-flash` | SAM AI 기능 도입 | 전체 | +| **2026-03-03** | **`gemini-2.0-flash` → `gemini-2.5-flash`** | **Google 2026-06-01 서비스 종료 예고** | **전체** | + +### 2026-03-03 변경 상세 + +**배경**: Google이 2026년 6월 1일부로 Gemini 2.0 Flash 모델 서비스를 종료한다는 통보를 함. + +**수정된 파일 (코드)**: + +| 프로젝트 | 파일 | 변경 내용 | +|----------|------|----------| +| API | `config/services.php` | fallback 기본값 변경 | +| API | `app/Services/AiReportService.php` | fallback 기본값 변경 | +| MNG | `config/services.php` | fallback 기본값 변경 | +| MNG | `app/Models/System/AiConfig.php` | DEFAULT_MODELS 상수 + getActiveGemini() fallback 변경 | +| MNG | `app/Services/NotionService.php` | fallback 기본값 변경 | +| MNG | `resources/views/system/ai-config/index.blade.php` | UI placeholder/기본값 변경 | +| MNG | `resources/views/google-cloud/ai-guide/index.blade.php` | 서비스 현황 모델명 변경 | +| MNG | `resources/views/academy/env-management.blade.php` | 환경 변수 예시 변경 | + +**수정된 .env (환경별)**: + +| 환경 | 수정 대상 | 담당 | +|------|----------|------| +| 로컬 api/.env | `GEMINI_MODEL=gemini-2.5-flash` | ✅ 완료 | +| 로컬 mng/.env | `GEMINI_MODEL=gemini-2.5-flash` | ✅ 완료 | +| 개발서버 api, mng | `GEMINI_MODEL=gemini-2.5-flash` | 배포 후 SSH 수정 필요 | +| 운영서버 api, mng | `GEMINI_MODEL=gemini-2.5-flash` | 개발팀장 직접 수정 | + +**수정하지 않은 파일 (의도적)**: + +| 파일 | 이유 | +|------|------| +| `api/database/migrations/` (3개) | 이미 실행 완료된 마이그레이션 — 변경 금지 | +| `cloud-api-pricing/index.blade.php` | `2.0 → 2.5` 마이그레이션 안내 UI — 이전 모델명이 의도적 | + +--- + +## 7. 모델 업데이트 워크플로우 + +> 상세 절차: [ai-model-update-workflow.md](./ai-model-update-workflow.md) + +### 7.1 요약 (7단계) + +``` +① 사전 확인 — 새 모델명, API 호환성, 가격 확인 +② 로컬 테스트 — .env 수정 → config:clear → 연결 테스트 +③ 코드 업데이트 — fallback 기본값 5곳 + 뷰 파일 +④ 개발서버 배포 — 코드 push + .env 수정 + 기능 테스트 +⑤ 단가 설정 — MNG 관리 화면에서 새 모델 단가 추가 +⑥ 운영서버 배포 — cherry-pick + .env 수정 (개발팀장) +⑦ 사후 모니터링 — 토큰 로그 확인 + 에러 로그 감시 (1일) +``` + +### 7.2 긴급 롤백 + +```bash +# .env만 이전 모델로 변경 (코드 배포 불필요) +GEMINI_MODEL=gemini-2.0-flash +php artisan config:clear +``` + +--- + +## 8. 비용 관리 + +### 8.1 토큰 단가 (ai_pricing_configs) + +| 모델 | 입력 ($/1M tokens) | 출력 ($/1M tokens) | 비고 | +|------|-------------------|--------------------|------| +| gemini-2.5-flash | 0.15 | 0.60 | 2026-03-03~ | +| gemini-2.0-flash | 0.10 | 0.40 | ~2026-06-01 종료 예정 | + +> 단가는 MNG `/system/ai-token-usage` → 단가 설정에서 관리 + +### 8.2 비용 계산 흐름 + +``` +API 호출 → 응답의 usageMetadata에서 토큰 수 추출 + ↓ +AiTokenHelper::saveGeminiUsage() + ↓ +ai_pricing_configs에서 단가 조회 (캐시 60분) + ↓ +ai_token_usages 테이블에 기록 (토큰 수, USD, KRW) +``` + +--- + +## 9. 신규 개발자 온보딩 체크리스트 + +AI 관련 작업을 시작하기 전: + +- [ ] 이 문서 전체 읽기 +- [ ] 로컬 `.env`에 `GEMINI_API_KEY`, `GEMINI_MODEL` 설정 확인 +- [ ] MNG `/system/ai-config` 화면에서 연결 테스트 성공 확인 +- [ ] AI 호출 서비스 파일 위치 파악 (섹션 4 참조) +- [ ] `AiConfig::getActiveGemini()` 사용법 이해 +- [ ] `AiTokenHelper::saveGeminiUsage()` 로 토큰 추적하는 패턴 이해 + +### 새 AI 기능 추가 시 + +```php +// 1. AiConfig에서 활성 설정 가져오기 +$config = AiConfig::getActiveGemini(); +if (!$config) throw new \RuntimeException('Gemini API 설정이 없습니다.'); + +// 2. API 호출 +$url = "{$config->base_url}/models/{$config->model}:generateContent?key={$config->api_key}"; +$response = Http::timeout(30)->post($url, [ ... ]); + +// 3. 토큰 사용량 기록 +AiTokenHelper::saveGeminiUsage( + $response->json()['usageMetadata'] ?? [], + $config->model, + '메뉴명' +); +``` + +--- + +## 관련 문서 + +| 문서 | 경로 | 설명 | +|------|------|------| +| AI 설정 기술문서 | `docs/guides/ai-config-settings.md` | DB 구조, 메서드, 코드 예시 | +| 모델 업데이트 워크플로우 | `docs/guides/ai-model-update-workflow.md` | 모델 변경 시 Step-by-Step 절차 | +| 변경 이력 | `docs/changes/20260303_gemini_model_upgrade.md` | 2.0→2.5 마이그레이션 상세 기록 | + +--- + +**최종 업데이트**: 2026-03-03 diff --git a/sam/docs/guides/ai-model-update-workflow.md b/sam/docs/guides/ai-model-update-workflow.md new file mode 100644 index 0000000..1b3a32a --- /dev/null +++ b/sam/docs/guides/ai-model-update-workflow.md @@ -0,0 +1,313 @@ +# AI 모델 업데이트 워크플로우 + +> **작성일**: 2026-03-03 +> **상태**: 확정 +> **대상**: Google Gemini, Claude, OpenAI 등 AI 모델 버전 업데이트 시 적용 + +--- + +## 1. 개요 + +### 1.1 목적 + +AI 제공사(Google, Anthropic, OpenAI)가 모델을 업데이트하거나 기존 모델을 종료(deprecate)할 때, SAM 시스템 전체를 안전하게 마이그레이션하기 위한 표준 절차를 정의한다. + +### 1.2 핵심 원칙 + +SAM의 AI 설정은 **환경변수 기반 아키텍처**로 설계되어 있어, 모델 변경 시 코드 수정이 최소화된다. + +``` +.env (GEMINI_MODEL=gemini-2.5-flash) ← ① 여기만 바꾸면 동작 + ↓ +config/services.php (env() + fallback 기본값) ← ② fallback도 업데이트 권장 + ↓ +AiConfig 모델 (DEFAULT_MODELS 상수) ← ③ 관리 화면 기본값 + ↓ +서비스 클래스 (config 또는 AiConfig 참조) ← 코드 수정 불필요 +``` + +--- + +## 2. 수정 대상 전체 매핑 + +### 2.1 환경변수 (.env) — 🔴 필수 + +| 환경 | 파일 위치 | 변수명 | +|------|----------|--------| +| 로컬 API | `/home/aweso/sam/api/.env` | `GEMINI_MODEL` | +| 로컬 MNG | `/home/aweso/sam/mng/.env` | `GEMINI_MODEL` | +| 개발서버 API | `/home/webservice/api/.env` | `GEMINI_MODEL` | +| 개발서버 MNG | `/home/webservice/mng/.env` | `GEMINI_MODEL` | +| 운영서버 API | `/home/webservice/api/.env` | `GEMINI_MODEL` | +| 운영서버 MNG | `/home/webservice/mng/.env` | `GEMINI_MODEL` | + +> **참고**: API와 MNG가 같은 `.env` 값을 사용하므로 둘 다 동일하게 변경해야 한다. +> **참고**: `GEMINI_API_KEY`와 `GEMINI_BASE_URL`은 모델 변경 시 대부분 그대로 유지된다. + +### 2.2 코드 Fallback 기본값 — 🟡 권장 + +코드에 하드코딩된 fallback 기본값. `.env`가 정상 설정되어 있으면 동작에 영향 없지만, 유지보수를 위해 함께 업데이트한다. + +| 파일 | 줄 | 현재 값 | +|------|---|---------| +| `api/config/services.php` | 46 | `env('GEMINI_MODEL', 'gemini-2.0-flash')` | +| `mng/config/services.php` | 40 | `env('GEMINI_MODEL', 'gemini-2.0-flash')` | +| `mng/app/Models/System/AiConfig.php` | 62 | `DEFAULT_MODELS['gemini'] = 'gemini-2.0-flash'` | +| `mng/app/Models/System/AiConfig.php` | 97 | `config('services.gemini.model', 'gemini-2.0-flash')` | +| `api/app/Services/AiReportService.php` | 326 | `config('services.gemini.model', 'gemini-2.0-flash')` | + +### 2.3 데이터베이스 — 🟢 필요 시 + +| 테이블 | 변경 내용 | 변경 방법 | +|--------|----------|----------| +| `ai_configs` | 모델명 변경 | MNG 관리 화면 (`/system/ai-config`) | +| `ai_pricing_configs` | 새 모델 단가 추가 | MNG 관리 화면 (`/system/ai-token-usage` → 단가 설정) | + +> `ai_token_usages` 테이블은 과거 기록이므로 수정 불필요. 새 호출부터 새 모델명으로 기록된다. + +### 2.4 Google API Base URL — 보통 변경 불필요 + +| 변수 | 현재 값 | 비고 | +|------|---------|------| +| `GEMINI_BASE_URL` | `https://generativelanguage.googleapis.com/v1beta` | v1beta → v1 변경 시에만 수정 | + +> Google이 API 버전을 올릴 때(v1beta → v1) Base URL도 변경 필요. 모델명만 바뀔 때는 그대로 유지. + +--- + +## 3. 실행 절차 (Step-by-Step) + +### Step 1: 사전 확인 (10분) + +```bash +# 1. 새 모델명 확인 (Google AI Studio 또는 공식 문서) +# 예: gemini-2.0-flash → gemini-2.5-flash + +# 2. API 호환성 확인 +# - Base URL 변경 여부 (v1beta → v1 등) +# - 요청/응답 스키마 변경 여부 +# - 가격 변경 여부 + +# 3. 현재 사용 중인 모델 확인 +grep -r "GEMINI_MODEL" /home/aweso/sam/api/.env /home/aweso/sam/mng/.env +``` + +--- + +### Step 2: 로컬 환경 테스트 (15분) + +```bash +# 1. 로컬 .env 수정 +# api/.env +GEMINI_MODEL=gemini-2.5-flash + +# mng/.env +GEMINI_MODEL=gemini-2.5-flash + +# 2. 캐시 클리어 (config가 캐시되어 있을 수 있음) +docker exec sam-api-1 php artisan config:clear +docker exec sam-mng-1 php artisan config:clear + +# 3. MNG 관리 화면에서 테스트 +# http://mng.sam.kr/system/ai-config → "연결 테스트" 버튼 + +# 4. 실제 기능 테스트 +# - 명함 OCR 테스트 (BusinessCardOcrService) +# - 사업자등록증 OCR 테스트 (TradingPartnerOcrService) +# - AI 리포트 생성 테스트 (AiReportService) +``` + +--- + +### Step 3: 코드 Fallback 업데이트 (5분) + +```bash +# Claude Code에게 요청: +# "Gemini 모델 fallback 기본값을 gemini-2.5-flash로 업데이트해줘" + +# 수정 대상 (5개 파일): +# 1. api/config/services.php +# 2. mng/config/services.php +# 3. mng/app/Models/System/AiConfig.php (DEFAULT_MODELS + getActiveGemini) +# 4. api/app/Services/AiReportService.php +``` + +--- + +### Step 4: 개발서버 배포 + 테스트 (10분) + +```bash +# 1. 코드 커밋 & 푸시 (Jenkins 자동 배포) +# "개발서버 푸시" + +# 2. 개발서버 .env 수정 (SSH 접속) +ssh pro@114.203.209.83 + +# API +cd /home/webservice/api +# .env 파일에서 GEMINI_MODEL 수정 +php artisan config:clear + +# MNG +cd /home/webservice/mng +# .env 파일에서 GEMINI_MODEL 수정 +php artisan config:clear + +# 3. 개발서버에서 기능 테스트 +# https://admin.codebridge-x.com/system/ai-config → 연결 테스트 +``` + +--- + +### Step 5: 단가 설정 업데이트 (5분) + +``` +# MNG 관리 화면 접속 +# /system/ai-token-usage → 단가 설정 탭 + +# 기존 모델 단가 비활성화 (삭제하지 않음 — 과거 기록 참조용) +# 새 모델 단가 추가: +# - provider: gemini +# - model_name: gemini-2.5-flash +# - input_price_per_million: (Google 공식 가격) +# - output_price_per_million: (Google 공식 가격) +# - exchange_rate: (현재 환율) +# - is_active: true +``` + +--- + +### Step 6: 운영서버 배포 (10분) + +```bash +# 1. 운영 코드 배포 +# "운영서버 푸시" + +# 2. 운영서버 .env 수정 (개발팀장이 직접) +# API: /home/webservice/api/.env → GEMINI_MODEL=gemini-2.5-flash +# MNG: /home/webservice/mng/.env → GEMINI_MODEL=gemini-2.5-flash +# php artisan config:clear (api, mng 각각) + +# 3. 운영서버 기능 확인 +``` + +--- + +### Step 7: 사후 모니터링 (1일) + +``` +# 1. AI 토큰 사용량 모니터링 +# /system/ai-token-usage → 새 모델명으로 로그 기록되는지 확인 + +# 2. 에러 로그 모니터링 +# API: storage/logs/laravel.log +# MNG: storage/logs/laravel.log + +# 3. 기존 모델 종료일 전까지 롤백 준비 +# .env의 GEMINI_MODEL만 이전 값으로 되돌리면 즉시 롤백 +``` + +--- + +## 4. 체크리스트 (모델 업데이트 시) + +### 사전 준비 + +- [ ] 새 모델명 확인 (공식 문서) +- [ ] API 호환성 확인 (Base URL, 스키마 변경 여부) +- [ ] 새 모델 가격 확인 + +### 로컬 테스트 + +- [ ] `api/.env` 의 `GEMINI_MODEL` 수정 +- [ ] `mng/.env` 의 `GEMINI_MODEL` 수정 +- [ ] Docker config:clear 실행 +- [ ] MNG AI 설정 화면에서 연결 테스트 성공 +- [ ] 명함 OCR / 사업자등록증 OCR / AI 리포트 테스트 + +### 코드 업데이트 + +- [ ] `api/config/services.php` fallback 기본값 변경 +- [ ] `mng/config/services.php` fallback 기본값 변경 +- [ ] `AiConfig.php` DEFAULT_MODELS 상수 변경 +- [ ] `AiConfig::getActiveGemini()` fallback 변경 +- [ ] `AiReportService.php` fallback 변경 +- [ ] Git 커밋 + +### 개발서버 + +- [ ] 코드 푸시 (Jenkins 배포) +- [ ] `.env` 수정 (api, mng) +- [ ] `config:clear` 실행 +- [ ] 연결 테스트 + 기능 테스트 + +### 단가 설정 + +- [ ] 기존 모델 단가 비활성화 +- [ ] 새 모델 단가 추가 (input/output 가격, 환율) + +### 운영서버 + +- [ ] 코드 푸시 (cherry-pick → main) +- [ ] `.env` 수정 (개발팀장 직접) +- [ ] `config:clear` 실행 +- [ ] 기능 확인 + +### 사후 관리 + +- [ ] 토큰 사용량 로그에 새 모델명 확인 +- [ ] 에러 로그 모니터링 (1일) +- [ ] 구 모델 종료일 전 롤백 가능 상태 유지 + +--- + +## 5. 긴급 롤백 절차 + +모델 변경 후 문제 발생 시: + +```bash +# 1. .env만 이전 모델로 변경 (코드 수정 불필요) +GEMINI_MODEL=gemini-2.0-flash + +# 2. 캐시 클리어 +php artisan config:clear + +# 3. 즉시 이전 모델로 복구됨 +``` + +> `.env` 기반 아키텍처의 장점: 코드 배포 없이 환경변수만 변경하면 즉시 롤백 가능 + +--- + +## 6. FAQ + +### Q: Base URL도 바꿔야 하나? + +A: 대부분 **변경 불필요**. Google이 API 버전을 올릴 때(예: `v1beta` → `v1`)에만 `GEMINI_BASE_URL`도 함께 변경한다. 모델명만 바뀔 때는 `GEMINI_MODEL`만 수정하면 된다. + +### Q: API 키도 바꿔야 하나? + +A: **변경 불필요**. 동일 프로젝트 내에서 모델이 바뀌어도 API 키는 유지된다. + +### Q: React 프로젝트도 수정해야 하나? + +A: **불필요**. React는 Google Maps API Key만 사용하며, Gemini AI 호출 코드가 없다. + +### Q: MNG 관리 화면에서만 바꾸면 안 되나? + +A: 현재 구조상 `AiConfig::getActiveGemini()`는 **DB가 아니라 .env 값을 읽는다**. DB의 `ai_configs` 테이블은 관리 화면 표시/테스트용이며, 실제 API 호출은 `.env` → `config()` 경로를 따른다. 따라서 `.env` 수정이 필수다. + +### Q: 향후 DB 기반으로 전환하면 더 편해지나? + +A: 맞다. `AiConfig::getActiveGemini()`가 DB에서 활성 설정을 읽도록 리팩토링하면, MNG 관리 화면에서만 모델을 바꿔도 전체 적용된다. 서버 SSH 접속 없이 웹에서 즉시 변경 가능해진다. 이는 향후 개선 과제로 검토할 수 있다. + +--- + +## 관련 문서 + +- [AI 설정 가이드](/home/aweso/sam/docs/guides/ai-config-settings.md) +- [서버 환경 비교](/home/aweso/sam/CLAUDE.md) — 실행 환경 섹션 + +--- + +**최종 업데이트**: 2026-03-03