306 lines
9.0 KiB
Markdown
306 lines
9.0 KiB
Markdown
|
|
# Google Cloud Storage (GCS) 설정 방법
|
||
|
|
|
||
|
|
## 개요
|
||
|
|
Google Speech-to-Text API에서 긴 오디오 파일(약 1분 이상)을 처리하려면 Google Cloud Storage에 파일을 업로드하고 GCS URI를 사용해야 합니다.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Google Cloud Storage 버킷 생성
|
||
|
|
|
||
|
|
### 1-1. Google Cloud Console 접속
|
||
|
|
1. [Google Cloud Console](https://console.cloud.google.com/) 접속
|
||
|
|
2. 프로젝트 선택 (예: `codebridge-chatbot`)
|
||
|
|
|
||
|
|
### 1-2. Storage 버킷 생성
|
||
|
|
1. 왼쪽 메뉴에서 **Cloud Storage** > **버킷** 클릭
|
||
|
|
2. **버킷 만들기** 클릭
|
||
|
|
3. 버킷 정보 입력:
|
||
|
|
- **이름**: `speech-audio-files` (또는 원하는 이름)
|
||
|
|
- **위치 유형**: **리전** 선택
|
||
|
|
- **위치**: `asia-northeast3` (서울) 또는 가까운 리전 선택
|
||
|
|
- **스토리지 클래스**: **Standard** (기본값)
|
||
|
|
- **액세스 제어**: **균일하게 적용** 선택
|
||
|
|
4. **만들기** 클릭
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. 서비스 계정에 Storage 권한 부여
|
||
|
|
|
||
|
|
### 2-1. IAM 권한 추가
|
||
|
|
1. **IAM 및 관리자** > **서비스 계정** 메뉴로 이동
|
||
|
|
2. 사용 중인 서비스 계정 선택 (예: `vertex-ai-client`)
|
||
|
|
3. **권한** 탭 클릭
|
||
|
|
4. **역할 부여** 클릭
|
||
|
|
5. 다음 역할 추가:
|
||
|
|
- **Storage 객체 관리자** (`roles/storage.objectAdmin`)
|
||
|
|
- 또는 **Storage 객체 생성자** (`roles/storage.objectCreator`) + **Storage 객체 뷰어** (`roles/storage.objectViewer`)
|
||
|
|
6. **저장** 클릭
|
||
|
|
|
||
|
|
### 2-2. 버킷별 권한 설정 (선택사항)
|
||
|
|
1. **Cloud Storage** > **버킷** 메뉴로 이동
|
||
|
|
2. 생성한 버킷 선택
|
||
|
|
3. **권한** 탭 클릭
|
||
|
|
4. **주 구성원 추가** 클릭
|
||
|
|
5. 서비스 계정 이메일 입력 (예: `vertex-ai-client@codebridge-chatbot.iam.gserviceaccount.com`)
|
||
|
|
6. 역할: **Storage 객체 관리자** 선택
|
||
|
|
7. **저장** 클릭
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. PHP 코드에 GCS 업로드 기능 추가
|
||
|
|
|
||
|
|
### 3-1. 방법 1: REST API 직접 사용 (추천 - 라이브러리 불필요)
|
||
|
|
|
||
|
|
서비스 계정을 사용하여 OAuth 2.0 토큰을 생성하고, Google Cloud Storage REST API를 직접 호출합니다.
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
- 추가 라이브러리 불필요
|
||
|
|
- 가볍고 빠름
|
||
|
|
- 기존 코드와 일관성 유지
|
||
|
|
|
||
|
|
**GCS 업로드 함수 (REST API 사용)**:
|
||
|
|
|
||
|
|
```php
|
||
|
|
function uploadToGCS($file_path, $bucket_name, $object_name, $service_account_path) {
|
||
|
|
// 1. OAuth 2.0 토큰 생성 (기존 코드 재사용)
|
||
|
|
$serviceAccount = json_decode(file_get_contents($service_account_path), true);
|
||
|
|
$now = time();
|
||
|
|
|
||
|
|
$jwtHeader = base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
|
||
|
|
$jwtClaim = base64_encode(json_encode([
|
||
|
|
'iss' => $serviceAccount['client_email'],
|
||
|
|
'scope' => 'https://www.googleapis.com/auth/devstorage.full_control',
|
||
|
|
'aud' => 'https://oauth2.googleapis.com/token',
|
||
|
|
'exp' => $now + 3600,
|
||
|
|
'iat' => $now
|
||
|
|
]));
|
||
|
|
|
||
|
|
$privateKey = openssl_pkey_get_private($serviceAccount['private_key']);
|
||
|
|
openssl_sign($jwtHeader . '.' . $jwtClaim, $signature, $privateKey, OPENSSL_ALGO_SHA256);
|
||
|
|
openssl_free_key($privateKey);
|
||
|
|
|
||
|
|
$jwt = $jwtHeader . '.' . $jwtClaim . '.' . base64_encode($signature);
|
||
|
|
|
||
|
|
// OAuth 토큰 요청
|
||
|
|
$tokenCh = curl_init('https://oauth2.googleapis.com/token');
|
||
|
|
curl_setopt($tokenCh, CURLOPT_POST, true);
|
||
|
|
curl_setopt($tokenCh, CURLOPT_POSTFIELDS, http_build_query([
|
||
|
|
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
||
|
|
'assertion' => $jwt
|
||
|
|
]));
|
||
|
|
curl_setopt($tokenCh, CURLOPT_RETURNTRANSFER, true);
|
||
|
|
curl_setopt($tokenCh, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
|
||
|
|
|
||
|
|
$tokenResponse = curl_exec($tokenCh);
|
||
|
|
$tokenData = json_decode($tokenResponse, true);
|
||
|
|
$accessToken = $tokenData['access_token'];
|
||
|
|
curl_close($tokenCh);
|
||
|
|
|
||
|
|
// 2. GCS에 파일 업로드
|
||
|
|
$file_content = file_get_contents($file_path);
|
||
|
|
$mime_type = mime_content_type($file_path) ?: 'audio/webm';
|
||
|
|
|
||
|
|
$upload_url = 'https://storage.googleapis.com/upload/storage/v1/b/' .
|
||
|
|
urlencode($bucket_name) . '/o?uploadType=media&name=' .
|
||
|
|
urlencode($object_name);
|
||
|
|
|
||
|
|
$ch = curl_init($upload_url);
|
||
|
|
curl_setopt($ch, CURLOPT_PUT, true);
|
||
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||
|
|
'Authorization: Bearer ' . $accessToken,
|
||
|
|
'Content-Type: ' . $mime_type,
|
||
|
|
'Content-Length: ' . strlen($file_content)
|
||
|
|
]);
|
||
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $file_content);
|
||
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
|
|
|
||
|
|
$response = curl_exec($ch);
|
||
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
|
|
curl_close($ch);
|
||
|
|
|
||
|
|
if ($code === 200) {
|
||
|
|
return 'gs://' . $bucket_name . '/' . $object_name;
|
||
|
|
} else {
|
||
|
|
error_log('GCS 업로드 실패: ' . $response);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3-2. 방법 2: PHP 클라이언트 라이브러리 사용
|
||
|
|
|
||
|
|
Google Cloud Storage PHP 클라이언트 라이브러리가 필요한 경우:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
composer require google/cloud-storage
|
||
|
|
```
|
||
|
|
|
||
|
|
**GCS 업로드 함수 (라이브러리 사용)**:
|
||
|
|
|
||
|
|
```php
|
||
|
|
function uploadToGCS($file_path, $bucket_name, $object_name, $service_account_path) {
|
||
|
|
require_once __DIR__ . '/vendor/autoload.php';
|
||
|
|
|
||
|
|
// 서비스 계정 인증
|
||
|
|
$client = new \Google\Cloud\Storage\StorageClient([
|
||
|
|
'keyFilePath' => $service_account_path
|
||
|
|
]);
|
||
|
|
|
||
|
|
$bucket = $client->bucket($bucket_name);
|
||
|
|
$object = $bucket->upload(
|
||
|
|
fopen($file_path, 'r'),
|
||
|
|
['name' => $object_name]
|
||
|
|
);
|
||
|
|
|
||
|
|
// GCS URI 생성
|
||
|
|
$gcs_uri = 'gs://' . $bucket_name . '/' . $object_name;
|
||
|
|
|
||
|
|
return $gcs_uri;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. process_meeting.php에 GCS 통합
|
||
|
|
|
||
|
|
### 4-1. 설정 파일 생성
|
||
|
|
`/apikey/gcs_config.txt` 파일 생성:
|
||
|
|
```
|
||
|
|
bucket_name=speech-audio-files
|
||
|
|
project_id=codebridge-chatbot
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4-2. 코드 수정
|
||
|
|
큰 파일(10MB 이상 또는 1분 이상)인 경우:
|
||
|
|
1. 파일을 GCS에 업로드
|
||
|
|
2. GCS URI (`gs://bucket-name/object-name`) 생성
|
||
|
|
3. Speech-to-Text API에 GCS URI 전달
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. GCS URI 형식
|
||
|
|
|
||
|
|
### 5-1. GCS URI 형식
|
||
|
|
```
|
||
|
|
gs://[BUCKET_NAME]/[OBJECT_NAME]
|
||
|
|
```
|
||
|
|
|
||
|
|
예시:
|
||
|
|
```
|
||
|
|
gs://speech-audio-files/meetings/20241201_143022_abc123.webm
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5-2. 공개 URL vs GCS URI
|
||
|
|
- **GCS URI**: `gs://bucket/object` (Google API에서 직접 접근)
|
||
|
|
- **공개 URL**: `https://storage.googleapis.com/bucket/object` (웹 브라우저 접근)
|
||
|
|
|
||
|
|
**참고**: Speech-to-Text API는 **GCS URI**만 지원합니다. 공개 URL은 작동하지 않습니다.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. 비용 고려사항
|
||
|
|
|
||
|
|
### 6-1. Storage 비용
|
||
|
|
- **Standard 스토리지**: 약 $0.020/GB/월
|
||
|
|
- **네트워크 전송**: 약 $0.12/GB (아시아 리전 간)
|
||
|
|
|
||
|
|
### 6-2. 최적화 방법
|
||
|
|
1. **수명 주기 규칙 설정**: 7일 후 자동 삭제
|
||
|
|
2. **Nearline 또는 Coldline 스토리지**: 장기 보관 시 사용
|
||
|
|
3. **자동 삭제**: STT 처리 후 즉시 삭제
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. 자동 삭제 설정 (수명 주기 규칙)
|
||
|
|
|
||
|
|
### 7-1. 수명 주기 규칙 생성
|
||
|
|
1. **Cloud Storage** > **버킷** 메뉴로 이동
|
||
|
|
2. 버킷 선택
|
||
|
|
3. **수명 주기** 탭 클릭
|
||
|
|
4. **규칙 추가** 클릭
|
||
|
|
5. 규칙 설정:
|
||
|
|
- **조건**: 객체가 7일 이상 되었을 때
|
||
|
|
- **작업**: **삭제** 선택
|
||
|
|
6. **만들기** 클릭
|
||
|
|
|
||
|
|
### 7-2. 코드에서 삭제
|
||
|
|
STT 처리 완료 후 PHP 코드에서 삭제:
|
||
|
|
|
||
|
|
```php
|
||
|
|
$object->delete();
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. 테스트 방법
|
||
|
|
|
||
|
|
### 8-1. 수동 테스트
|
||
|
|
1. Google Cloud Console에서 버킷에 파일 업로드
|
||
|
|
2. GCS URI 확인: `gs://bucket-name/file-name`
|
||
|
|
3. Speech-to-Text API에 GCS URI 전달하여 테스트
|
||
|
|
|
||
|
|
### 8-2. 코드 테스트
|
||
|
|
1. 작은 파일(30초 이하)로 먼저 테스트
|
||
|
|
2. 큰 파일(1분 이상)로 GCS 업로드 테스트
|
||
|
|
3. 오류 로그 확인
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. 문제 해결
|
||
|
|
|
||
|
|
### 9-1. 권한 오류
|
||
|
|
- **증상**: "Permission denied" 오류
|
||
|
|
- **해결**: 서비스 계정에 Storage 권한 확인
|
||
|
|
|
||
|
|
### 9-2. 버킷을 찾을 수 없음
|
||
|
|
- **증상**: "Bucket not found" 오류
|
||
|
|
- **해결**: 버킷 이름과 프로젝트 ID 확인
|
||
|
|
|
||
|
|
### 9-3. 파일 업로드 실패
|
||
|
|
- **증상**: 업로드 중 오류
|
||
|
|
- **해결**:
|
||
|
|
- 파일 크기 확인
|
||
|
|
- 네트워크 연결 확인
|
||
|
|
- 서비스 계정 권한 확인
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 10. 보안 고려사항
|
||
|
|
|
||
|
|
### 10-1. 버킷 액세스 제어
|
||
|
|
- **공개 버킷**: 모든 사용자가 읽기 가능 (비추천)
|
||
|
|
- **비공개 버킷**: 서비스 계정만 접근 (권장)
|
||
|
|
|
||
|
|
### 10-2. 서명된 URL (선택사항)
|
||
|
|
임시 접근 URL 생성 (1시간 유효):
|
||
|
|
|
||
|
|
```php
|
||
|
|
$url = $object->signedUrl(new \DateTime('+1 hour'));
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 11. 요약 체크리스트
|
||
|
|
|
||
|
|
- [ ] Google Cloud Storage 버킷 생성
|
||
|
|
- [ ] 서비스 계정에 Storage 권한 부여
|
||
|
|
- [ ] 버킷 이름과 프로젝트 ID 확인
|
||
|
|
- [ ] PHP 코드에 GCS 업로드 기능 추가
|
||
|
|
- [ ] 수명 주기 규칙 설정 (자동 삭제)
|
||
|
|
- [ ] 테스트 실행 및 확인
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 12. 참고 자료
|
||
|
|
|
||
|
|
- [Google Cloud Storage 문서](https://cloud.google.com/storage/docs)
|
||
|
|
- [PHP 클라이언트 라이브러리](https://github.com/googleapis/google-cloud-php-storage)
|
||
|
|
- [Speech-to-Text API 문서](https://cloud.google.com/speech-to-text/docs)
|
||
|
|
- [GCS URI 사용 가이드](https://cloud.google.com/speech-to-text/docs/async-recognize)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**작성일**: 2024년
|
||
|
|
**프로젝트**: 5130 (voice_ai 시스템)
|
||
|
|
|