티스토리 뷰
최근 AI 서비스가 어떤 것들이 있나 알아보면서(내년 사업 계획의 일환)
괜찮아 보이는 서비스가 있어서 한번 사용해보고 공유해 보려고 한다.
조사하기 앞서 몇 가지 조건이 붙었는데
1. 텍스트 기반으로 무언가를 할 수 있어야 한다.
2. AI를 사용한 서비스면 좋다.
3. API를 제공해야 한다.
위 조건을 모두 만족하는 서비스 중에서, 내가 조사한 것 중에 가장 괜찮아보였던 서비스는 D-ID 였다.
여러가지 서비스를 제공하는데,
그 중에서 가장 괜찮아 보이는 기능은 텍스트를 입력하면 그걸 사람 얼굴이 움직이면서 읽어준다는 것이다.
내가 사용하려는 기능은 API 키가 필요하기 때문에 회원가입을 해줘야한다.
로그인을 눌렀을 때 게스트페이지에서 Settings/API 를 누르면 회원가입을 하라고 나온다.
회원 가입을 진행하고나서 API Key를 발급 받는다.
API Key는 다시 안보여주니 잘 저장해두자. 그리고 credit이 들어온 것도 확인
테스트 용도로 credit을 아껴써야하는게, 영상 15초당 1credit이기 때문에 많이 못 써본다.
Twilio에 비해서 많이 짜다.
좌측에 Developer Hub로 진입하면 아래와 같은 페이지로 들어가게 되는데, 필요한건 Talks 부분이다.
여기서부터 작성할 내용은 이 페이지에 자세히 작성되어 있다. 그리고, 친절하게 영상도 다 제공한다.
(Postman만으로도 사용이 가능하다)
이제 구현해보자.
사전 준비
가장 중요한건 API key 지만, 몇 가지 더 필요한 게 있다.
반드시 필요한 건 Presenter의 URL 이다.
Presenter 사진은 D-ID에서 제공하는 걸 가져다쓰면 된다.
우 클릭 후 이미지 URL 복사해두자.
https://create-images-results.d-id.com/DefaultPresenters/Emma_f/image.jpeg
감정도 넣을 수 있으므로 자기가 쓰고 싶은 감정을 하나 선택한다.
그리고 한글도 지원한다. TTS를 Microsoft걸 지원하기 때문에, 어떤 목소리를 사용할지 찾아놓자.
https://learn.microsoft.com/ko-kr/azure/ai-services/speech-service/language-support?tabs=tts
이제 코드로 넘어간다.
구현
단순 외부 연결만을 하는 것이므로 특별한 코드는 없다.
Model
요청 객체 하나만 사용했다.
@FeignClient(name = "D-ID Client", url = "https://api.d-id.com", configuration = {DIdRequestHeader.class})
public interface DidFeignClient {
@PostMapping("/talks")
Object generateDidTalksVideo(@RequestBody DidVideoGenerateRequestDto didVideoGenerateRequestDto);
@GetMapping("talks")
Object getDidTalksVideo(String id);
}
Controller
@RestController
@RequiredArgsConstructor
public class DidController {
private final DidService didService;
@PostMapping("/talks")
public ResponseEntity<Object> generateVideo(@RequestBody Object didVideoGenerateRequestDto) {
Object resultObject = didService.generateVideo(didVideoGenerateRequestDto);
return ResponseEntity.ok(resultObject);
}
@GetMapping("/talks/{id}")
public ResponseEntity<Object> getVideo(@PathVariable String id) {
Object resultObject = didService.getVideo(id);
return ResponseEntity.ok(resultObject);
}
}
Service
@Service
@RequiredArgsConstructor
public class DidService {
private final DIDFeignClient didFeignClient;
public Object generateVideo(Object didVideoGenerateRequestDto) {
return didFeignClient.generateDidTalksVideo(didVideoGenerateRequestDto);
}
public Object getVideo(String id) {
return didFeignClient.getDidTalksVideo(id);
}
}
Client
@FeignClient(name = "didClient", url = "https://api.d-id.com", configuration = {DIdRequestHeader.class})
public interface DIDFeignClient {
@PostMapping("/talks")
Object generateDidTalksVideo(@RequestBody Object didVideoGenerateRequestDto);
@GetMapping("/talks/{id}")
Object getDidTalksVideo(@PathVariable String id);
}
헤더는 Github에서 확인
요청을 날려보자.
그럼 아래와 같은 결과가 온다.
필요한건 id다. id를 복사하고 PathVariable로 전달해줘야한다.
Get 요청을 날려주면 아래와 같은 긴 응답이 나온다.
{
"user": {
"features": [
"stitch",
"clips:write",
null
],
"stripe_plan_group": "deid-trial",
"authorizer": "basic",
"owner_id": "google-oauth2|105759186747154018860",
"id": "google-oauth2|105759186747154018860",
"plan": "deid-trial",
"email": "kimdongha15@gmail.com"
},
"script": {
"length": 24,
"ssml": false,
"subtitles": false,
"type": "text",
"provider": {
"type": "microsoft",
"voice_id": "ko-KR-JiMinNeural"
}
},
"metadata": {
"driver_url": "bank://lively/driver-06/original",
"mouth_open": false,
"num_faces": 1,
"num_frames": 126,
"processing_fps": 45.60790450139159,
"resolution": [
512,
512
],
"size_kib": 1507.0439453125
},
"audio_url": "https://d-id-talks-prod.s3.us-west-2.amazonaws.com/google-oauth2%7C105759186747154018860/tlk_rr22CFTkc7HmT-a0jbQQn/microsoft.wav?AWSAccessKeyId=AKIA5CUMPJBIK65W6FGA&Expires=1700403102&Signature=ZVtibtcrA1jrCaO11HcE21MxTcg%3D&X-Amzn-Trace-Id=Root%3D1-6558c61d-61b4b41471c5c04805bbb832%3BParent%3D40bba0ea7c144189%3BSampled%3D0%3BLineage%3Da08e19fe%3A0",
"created_at": "2023-11-18T14:11:42.527Z",
"face": {
"mask_confidence": -1,
"detection": [
224,
198,
484,
553
],
"overlap": "no",
"size": 512,
"top_left": [
98,
119
],
"face_id": 0,
"detect_confidence": 0.9998306035995483
},
"config": {
"stitch": false,
"pad_audio": 0,
"align_driver": true,
"sharpen": true,
"reduce_noise": false,
"auto_match": true,
"normalization_factor": 1,
"show_watermark": true,
"motion_factor": 1,
"result_format": ".mp4",
"fluent": false,
"align_expand_factor": 0.3
},
"source_url": "https://d-id-talks-prod.s3.us-west-2.amazonaws.com/google-oauth2%7C105759186747154018860/tlk_rr22CFTkc7HmT-a0jbQQn/source/image.jpeg?AWSAccessKeyId=AKIA5CUMPJBIK65W6FGA&Expires=1700403102&Signature=piYnFEAJ8gwZV3a7CTB%2FqB1E%2BEo%3D&X-Amzn-Trace-Id=Root%3D1-6558c61d-61b4b41471c5c04805bbb832%3BParent%3D40bba0ea7c144189%3BSampled%3D0%3BLineage%3Da08e19fe%3A0",
"created_by": "google-oauth2|105759186747154018860",
"status": "done",
"driver_url": "bank://lively/",
"modified_at": "2023-11-18T14:11:46.045Z",
"user_id": "google-oauth2|105759186747154018860",
"subtitles": false,
"id": "tlk_rr22CFTkc7HmT-a0jbQQn",
"duration": 5.064,
"started_at": "2023-11-18T14:11:42.571",
"result_url": "https://d-id-talks-prod.s3.us-west-2.amazonaws.com/google-oauth2%7C105759186747154018860/tlk_rr22CFTkc7HmT-a0jbQQn/1700316702527.mp4?AWSAccessKeyId=AKIA5CUMPJBIK65W6FGA&Expires=1700403106&Signature=tO0lJNYg7StfQkYWP%2B48A2sZm18%3D&X-Amzn-Trace-Id=Root%3D1-6558c622-0792718c4a6c45f9416347d1%3BParent%3De3e219eb4d0c22d8%3BSampled%3D1%3BLineage%3D6b931dd4%3A0"
}
마지막 result_url으로 비디오를 다운받을 수 있다.
정확히는 모르겠지만 저장기간이 24시간 이라는 것 같다.
추가적으로 webhook을 걸어서, 영상 생성이 완료되면 응답을 받는 기능도 있는 것 같지만 여기선 사용하지 않았다.
단점
솔직히 다양한 서비스를 써보면서 이 서비스만큼 편하고 좋은 서비스를 써본적이 없다.
그런데, 단점은 딱 하나다.
비싸다.
15초당 크레딧이 하나씩 빠진다. 그런데 가격이 올라도 제공하는 크레딧은 많이 늘어나질 않는다.
아래는 15초짜리 영상을 두 번 만든 내 계정의 크레딧이다.
Github
https://github.com/imsosleepy/d-id-java.git
마치며
간만에 재밌는 서비스를 써봐서 한번 소개해봤다.
짧게 끊고 싶었지만, 이리저리 길어져버렸다.
이제부터는 github도 조금씩 살려보려고한다.
- Total
- Today
- Yesterday
- Spring
- 티스토리챌린지
- JWT
- docker
- OpenFeign
- springboot
- elasticsearch
- 오블완
- 후쿠오카
- EKS
- Kotlin
- ChatGPT
- cache
- Elastic cloud
- lambda
- terraform
- 스프링부트
- 람다
- OpenAI
- AOP
- AWS EC2
- Log
- java
- GIT
- AWS
- serverless
- openAI API
- CloudFront
- S3
- MySQL
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |