지난번에 플러터 패키지를 이용해 stt를 구현했었다.
https://day4fternoon.tistory.com/126
[Flutter] speech_to_text로 음성 인식 구현하기
AI 채팅봇과 대화할 수 있는 채팅 페이지를 만드는데, 타이핑뿐만 아니라 음성으로도 메시지를 입력할 수 있게 해야 한다.speech_to_text 플러터 패키지를 사용해 구현할 수 있다. https://pub.dev/packages
day4fternoon.tistory.com
이제 만들 것은 반대로 챗봇 즉 AI의 채팅을 목소리로 읽어주는 기능이다. 대화 감상이 주제이므로 대화하는 느낌을 내기 위해 AI 채팅을 tts로 변환해보도록 하겠다.
stt 때는 speech_to_text라는 플러터 패키지로 간단히 구현했었다. tts도 플러터 패키지로 구현할 수 있긴 한데,
https://pub.dev/packages/flutter_tts
flutter_tts | Flutter package
A flutter plugin for Text to Speech. This plugin is supported on iOS, macOS, Android, Web, & Windows.
pub.dev
한국어 목소리가 여자하나 남자하나? 여튼 목소리 개수가 너무 한정적이었다.
나는 최소 4개의 목소리가 필요했으므로... 패키지 사용 대신 OpenAI tts API를 사용하기로 했다.
https://platform.openai.com/docs/guides/text-to-speech
6개의 목소리를 지원하긴 하는데 솔직히 내가 원하는 느낌은 아니었다... 좀더 귀엽고큐티친근한 목소리가 나왔으면 좋겠는데 일단 이건 해결할 수 있는 부분이 아니니, 목소리 개수가 좀 된다는 것만으로도 만족하고 사용하기로 헀다.
1. OpenAI 기본 설정하기
웬만한 오픈AI의 API는 플러터 프로젝트에서 dart_openai를 가지고 사용할 수 있다.
https://pub.dev/packages/dart_openai
dart_openai | Dart package
Dart SDK for openAI Apis (GPT-3 & DALL-E), integrate easily the power of OpenAI's state-of-the-art AI models into their Dart applications.
pub.dev
OpenAI API를 사용하려면 API 키가 필요하다. 오픈ai에 돈 내면 API키를 준다.
그리고 api키처럼 유출되면 안 되는 값은 환경변수 파일 .env를 만들어 따로 관리해주어야 한다.
플러터 프로젝트에서 .env를 설정하려면 패키지 설치 및 각종 설정이 필요하다. (위 dart_openai 문서에도 초기설정이 잘 나와있다)
1) 루트디렉토리에 .env파일을 만들고 API키를 적는다.
2) envied 패키지 설치한다
https://pub.dev/packages/envied
envied | Dart package
Explicitly reads environment variables into a dart file from a .env file for more security and faster start up times.
pub.dev
얘네 다 설치해야된다
$ flutter pub add envied
$ flutter pub add --dev envied_generator
$ flutter pub add --dev build_runner
3) lib/env 폴더를 만들고 안에 env.dart 파일 만든 뒤 내용 작성
빨간줄이 뜰 텐데 일단 놔둬도 된다. env.g.dart 파일이 아직 없어서 생기는 문제이므로...
공식문서에는 없던데 apiKey 선언할 때 자료형도 같이 적어줘야 빌드가 정상적으로 된다.
import 'package:envied/envied.dart';
part 'env.g.dart';
@Envied(path: ".env")
abstract class Env {
@EnviedField(varName: 'OPEN_AI_API_KEY') // the .env variable.
static const String apiKey = _Env.apiKey;
}
4) 빌드 실행
터미널에
$ dart run build_runner build
입력해서 빌드 실행하면 env폴더에 env.g.dart 파일이 생성되고 빨간줄이 없어진다. 그럼 설정 끝
5) .gitignore 설정
api키는 유출되면 안되니까 .gitignore에 .env와 env.g.dart를 추가해주면 진짜 끝
2. TTS API 사용하기
dart_openai 패키지 공식문서를 쭉 내리다보면 speech를 어떻게 사용하는지 나온다.
참고해서 함수를 만들어주자.
봇채팅 위젯에 tts를 위한 재생버튼을 하나 추가해주고 여기 onPress에 할당할 함수를 만들것이다
Future<void> getSpeech() async {
OpenAI.apiKey = Env.apiKey;
final directory = await getApplicationCacheDirectory();
final speechOutputDir = Directory('${directory.path}/speechOutput');
if (!speechOutputDir.existsSync()) {
await speechOutputDir.create(recursive: true);
}
File speechFile = await OpenAI.instance.audio.createSpeech(
model: "tts-1",
input: message,
voice: "nova",
responseFormat: OpenAIAudioSpeechResponseFormat.mp3,
outputDirectory: speechOutputDir,
);
print(speechFile.path);
}
공식문서 그대로 디렉토리를 지정했더니 OS가 어쩌구 오류가 나서... 존재하지 않는다면 디렉토리를 create해라 하는 부분을 추가했다. 디버그 콘솔에 요청하고 받아와서 어쩌구 저쩌구 잘 됐고 어쩌구 그런 것들이 뜬다면 성공이다.
메시지를 스피치 즉 mp3파일로 변환하고 지정한 디렉토리에 저장한다.
근데 우리가 원하는 건 파일형태가 아니라 내 귀로 들어야 할 것 아닌가
그러기 위해 mp3 재생을 위한 패키지를 찾아봣고 audioplayers라는 패키지가 있다. 이걸 쓰기로 했다.
3. audioplayers 패키지 사용해 mp3파일 읽기
https://pub.dev/packages/audioplayers
audioplayers | Flutter package
A Flutter plugin to play multiple audio files simultaneously
pub.dev
사용법은 간단하다. 플레이어를 만들고 재생할 파일 경로를 입력해주기만 하면 된다.
Future<void> getSpeech() async {
OpenAI.apiKey = Env.apiKey;
final directory = await getApplicationCacheDirectory();
final speechOutputDir = Directory('${directory.path}/speechOutput');
if (!speechOutputDir.existsSync()) {
await speechOutputDir.create(recursive: true);
}
File speechFile = await OpenAI.instance.audio.createSpeech(
model: "tts-1",
input: message,
voice: "nova",
responseFormat: OpenAIAudioSpeechResponseFormat.mp3,
outputDirectory: speechOutputDir,
);
print(speechFile.path);
final player = AudioPlayer();
await player.play(UrlSource('file://${speechFile.path}'));
}
한가지 알아야 할 점은 파일 경로에 file:// 스킴을 추가해줘야 한다는 것...
그럼 이제 잘 작동한다.
결과물
귀여운 얼굴에 그렇지 못한 목소리지만... ...
오픈에이아이각성하라. 멋진목소리를만들도록
여튼 이런식으로 잘 작동한다. 굿 👌
'기록' 카테고리의 다른 글
[A.(에이닷)] LLM과 함께하는 쉬운 글쓰기 (1) | 2024.09.30 |
---|---|
[에이닷(A.)] 하이 멀티LLM, 잼얘해줘! (5) | 2024.09.19 |
[Flutter] speech_to_text로 음성 인식 구현하기 (1) | 2024.09.03 |
[React] 카카오API로 내 위치에서 지도 검색하기(1) (2) | 2024.08.15 |
레오니드 팬 페이지 만들기(2) (0) | 2024.02.23 |