Django Rest Framework 를 이용한 REST API 서버로
- TTS 프로젝트 생성, 조회, 수정, 삭제 기능
- TTS 프로젝트 내 TTS 데이터 생성, 조회, 수정, 삭제 기능
- TTS 데이터 다운로드
- 인증 / 인가
- 테스트
위 기능을 제공합니다.
- 텍스트를 음성으로 변환하는 기술
- 입력 받은 텍스트를 음성 파일로 변환
- 2022/09/22~2022/09/27 (4일)
✅ 로그인한 유저만 접근 가능합니다.
apps/utils.py
- Google에서 제공하는
gTTS
모듈을 사용 - 입력 데이터 전처리 함수 구현(
preprocess_data
)- 한글, 영어, 숫자, 물음표, 느낌표, 마침표, 따옴표, 공백을 제외하고 허용 x
- 빈 문장 허용 x
- 마침표(.), 물음표(?), 느낌표(!) 로 문장 구분
- 전처리 데이터 → 음성 파일 변환 함수 구현(
convert_data
)gTTS
함수를 사용해서 음성 파일로 변환 뒤 지정 위치에 저장- 음성 파일 생성시 식별자 발급(
data_id
)
- 오디오 생성 위치 및 파일명
/audio/{project_id}/{data_id}.mp3
- 프로젝트 생성시
- 여러 문장으로 이루어진 긴 문자열을 입력받고
- 해당 문자열을 문장 단위로 분리하여 TTS 변환(음성 파일 생성)
- 생성된 음성파일 관련 데이터는 TTSData 모델에 저장
- 프로젝트명 수정 가능
- 본인의 프로젝트 조회 가능
- 프로젝트 삭제시 해당 프로젝트의 음성 파일이 담겨있는 폴더도 함께 삭제
- TTS 데이터 생성시
- 입력 받은 문자열을 전처리 하고 음성 파일로 변환한 후
- 발급받은 식별자(data_id) 및 전처리한 텍스트, 속도 및 기타 데이터 저장
- 생성시 문장의 위치 설정 가능
- 입력으로
order: n
을 받게 되면 - n번째 (1 ≤ n ≤ 프로젝트 내 tts 데이터 개수 + 1) 위치에 문장을 저장한다는 의미
- 기존에 저장돼있던 n ~ 끝번까지
order = order + 1
처리 - 조회시
order
필드로 정렬
- 해당 작업은 동시에 실행할 경우 데이터 정합성이 깨질 우려가 있으므로
@transaction.atomic()
사용
- 입력으로
text
,speed
변경 가능 (위치 수정 불가능 → 추후 수정할 예정)text
변경시 생성 과정(문장 위치 설정 제외) 다시 반복- 기존 데이터의
data_id
,text
,path
변경
- 기존 데이터의
order
필드 오름차순으로 정렬- 한 번에 10개씩 볼 수 있도록 Pagination 구현
- 삭제시 해당 오디오 파일도 같이 삭제
- 데이터 다운로드 가능
.mp3
,.wav
확장자 파일 전송을 위해 django의HTTPResponse
이용Content-Type
:audio/mpeg
- 해당 url로 접근시 바로 다운로드
- 바로 다운로드 되지 않고 유저에게 확인 절차를 거칠 수 있는지 고민중
simpleJWT
를 이용한 토큰 인증 방식 구현- 현재는 django admin 사이트에서 (혹은 db에 직접) 유저 생성
- 회원가입은 추후 구현할 예정
-
rest_framework
의APITestCase
이용 -
프로젝트
- 프로젝트 생성 테스트
- 성공
- 프로젝트 조회 테스트
- 성공
- 실패: 다른 유저의 프로젝트를 요청한 경우(권한)
- 프로젝트 생성 테스트
-
TTS 데이터
- 데이터 생성 테스트
- 성공
- 실패: 입력 문장이 여러 개인 경우
- 실패: 입력 순서가 유효하지 않은 경우
- 데이터 수정 테스트
- 성공
- 실패: 입력 문장이 없는 경우
- 데이터 삭제 테스트
- 성공
- 데이터 생성 테스트
버전 | 기능 | 세부 기능 | 설명 | 상태 |
---|---|---|---|---|
v1 | 프로젝트 | 생성 | 프로젝트 및 TTS데이터 생성 | ✅ |
- | - | 조회 | 프로젝트 조회 | ✅ |
- | - | 수정 | 프로젝트 수정 | ✅ |
- | - | 삭제 | 프로젝트 삭제 | ✅ |
- | 데이터 | 생성 | TTS 데이터 생성 | ✅ |
- | - | 조회 | TTS 데이터 조회 (메타데이터) | ✅ |
- | - | 수정 | TTS 데이터 (텍스트, 속도) 수정 | ✅ |
- | - | 삭제 | TTS 데이터 및 오디오 파일 삭제 | ✅ |
- | - | 조회 | 쿠폰 사용 내역 통계 | ✅ |
- | - | 다운로드 | TTS 데이터 파일 다운로드 | ✅ |
- | 유저 | 인증 / 인가 | 로그인 기능 및 권한 설정 | ✅ |
- | 테스트 | 테스트 | 기능, 전체 테스트 | ✅ |
🔥 추가 기능 구현시 업데이트 예정
- User model
- User 모델은 Django의
AbstractUser
를 overriding
- User 모델은 Django의
- Project model
- URL 접근시 DB PK 대신
project_id
(unique) 사용 - USER ↔ PROJECT (1:N)
- URL 접근시 DB PK 대신
- TTSData model
- URL 접근시 DB PK 대신
data_id
(unique) 사용 - PROJECT ↔ TTSDATA (1:N)
- 프로젝트별로 문장 순서 정렬(
order_by='order'
)
- URL 접근시 DB PK 대신
- URL:
POST /api/v1/projects/
- Request
{
"title": "프로젝트 명",
"text": "음성 파일로 변환할 문장. 여러 문장을 입력으로 받을 수 있음.",
"speed": 1.0
}
- Response
- status:
201 Created
- status:
{
"project_id": "프로젝트 id",
"title": "프로젝트 명",
"created_at": "2022-09-27T03:07:23.394805",
"updated_at": "2022-09-27T03:07:23.394805",
"user": "유저 id"
}
- URL:
PUT /api/v1/projects/:project_id/
- Request
{
"title": "프로젝트 명 수정",
}
- Response
- status:
200 OK
- status:
{
"project_id": "프로젝트 id",
"title": "프로젝트 명 수정",
"created_at": "2022-09-27T03:07:23.394805",
"updated_at": "2022-09-27T03:07:23.394805",
"user": "유저 id"
}
-
URL:
GET /api/v1/projects/
-
Response
- status:
200 OK
- status:
[
{
"project_id": "프로젝트 id",
"title": "프로젝트 명 수정",
"created_at": "2022-09-27T03:07:23.394805",
"updated_at": "2022-09-27T03:07:23.394805",
"user": "유저 id"
},
...
]
-
URL:
GET /api/v1/projects/:project_id/
-
Response
- status:
200 OK
- status:
{
"project_id": "프로젝트 id",
"title": "프로젝트 명 수정",
"created_at": "2022-09-27T03:07:23.394805",
"updated_at": "2022-09-27T03:07:23.394805",
"user": "유저 id"
}
-
URL:
DELETE /api/v1/projects/:project_id/
-
Response
- status:
204 NO CONTENT
- status:
- URL:
POST /api/v1/projects/:project_id/data/
- Request
{
"text": "데이터 테스트입니다.",
"speed": 1.0,
"order": 1
}
- Response
- status:
201 Created
- status:
{
"text": "데이터 테스트입니다",
"speed": 1.0,
"order": 1
}
- URL:
PUT /api/v1/projects/:project_id/data/:data_id/
- Request
{
"text": "데이터 명 수정!",
"speed": 1.0
}
- Response
- status:
200 OK
- status:
{
"text": "데이터 명 수정",
"speed": 1.0,
"order": 1
}
-
URL:
GET /api/v1/projects/:project_id/data/?pages=
-
Response
- status:
200 OK
- status:
{
"count": 6,
"next": "다음 페이지 URL",
"previous": "이전 페이지 URL",
"results": [
{
"project_id": "000002468b",
"data_id": "220927211620779",
"text": "안녕하세요",
"speed": 1.0,
"order": 1,
"created_at": "2022-09-27T21:16:22.501291",
"updated_at": "2022-09-27T21:16:22.502292"
},
{
"project_id": "000002468b",
"data_id": "22092721162058e",
"text": "반갑습니다",
"speed": 1.0,
"order": 2,
"created_at": "2022-09-27T21:16:22.502292",
"updated_at": "2022-09-27T21:16:22.502292"
},
{
"project_id": "000002468b",
"data_id": "22092721174670f",
"text": "오늘은 9월 28일 수요일 입니다",
"speed": 1.0,
"order": 3,
"created_at": "2022-09-27T21:16:22.502292",
"updated_at": "2022-09-27T21:17:47.060966"
},
{
"project_id": "000002468b",
"data_id": "220927211621ae2",
"text": "좋은 하루 되세요",
"speed": 1.0,
"order": 4,
"created_at": "2022-09-27T21:16:22.502292",
"updated_at": "2022-09-27T21:16:22.502292"
},
...
]
}
-
URL:
GET /api/v1/projects/:project_id/data/:data_id/
-
Response
- status:
200 OK
- status:
{
"project_id": "000002468b",
"data_id": "22092721174670f",
"text": "오늘은 9월 28일 수요일 입니다",
"speed": 1.0,
"order": 3,
"created_at": "2022-09-27T21:16:22.502292",
"updated_at": "2022-09-27T21:17:47.060966"
}
-
URL:
DELETE /api/v1/projects/:project_id/data/:data_id/
-
Response
- status:
204 NO CONTENT
- status:
-
URL:
GET /api/v1/projects/:project_id/data/:data_id/download/
-
Response(HTTP Response)
- status:
200 OK
- response.body에 파일 첨부
- status:
├── apps
│ ├── account
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── project
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── paginations.py
│ │ ├── serializers.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── urls.py
│ └── utils.py
├── audio
├── config
│ ├── asgi.py
│ ├── settings
│ │ ├── base.py
│ │ ├── dev.py
│ │ ├── prod.py
│ │ └── test.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── requirements.txt
- 로컬에서 실행할 경우
# 프로젝트 clone(로컬로 내려받기)
git clone -b develop --single-branch ${github 주소}
cd ${디렉터리 명}
# 가상환경 설정
python -m venv ${가상환경명}
source ${가상환경명}/bin/activate
# window (2 ways)
# 1> ${가상환경명}/Scripts/activate
# 2> activate
# 라이브러리 설치
pip install -r requirements.txt
# 실행
python manage.py runserver