

이미 TTS봇을 만들었는데 뭘 또 같은 걸 만드냐 싶겠지만, google-tts는 속도 조절이 안된다. 그리고 지원해줄 생각도 없어보이고.
그래서 다른 TTS를 찾아본 결과, NaverTTS가 있었다.
그런데 이게 파이썬 전용이었다. JS로는 더는 뾰족한 수가 보이지 않아서 이번에는 파이썬으로 만들어봤다.
전체 소스코드는 하단 링크 참고
https://github.com/HYK-Nov/polite-tts-bot-py
이번에는 당연하지만 discord.py를 사용할 것이다.
봇 생성까지는 기존과 동일하다.
pip install discord.py discord.py[voice] NaverTTS
discord.py: 디스코드 봇을 만들기 위함discord.py[voice]: 음성채널에서 음성 재생을 위함NaverTTS: TTS 음원from dotenv import load_dotenv
load_dotenv()
BOT_TOKEN = os.getenv('BOT_TOKEN')
VOICE_CHANNEL_ID = os.getenv('VOICE_CHANNEL_ID')
TEXT_CHANNEL_ID = os.getenv('TEXT_CHANNEL_ID')
Github에 올릴 예정이라면 .env를 통해서 미리 토큰이나 채널ID 정보를 분리해두자
intents = discord.Intents.default()
intents.message_content = True
bot = Bot('', intents=intents)
파이썬은 봇 정보를 따로 만들어줘한다. TTS를 위해서는 메세지 정보를 수신해야하므로 intents.message_content = True 설정을 해주자.
Bot은 command_prefix라고 명령어를 수신하기 위해 !나 / 등을 지정할 수 있다.
예를 들어 /tts 읽어줘 하면 tts라는 명령어를 실행하는 것이다.
여기서는 번거로우니 특정한 키워드 없이 메세지를 올리기만 하면 실행되도록 비워뒀다.
disconnect_timer = None
이것도 해두자. 어디에 쓸 건지는 아래에 있으니 계속 보면 알 수 있을 것이다.
@bot.event
async def on_ready():
print(f'We have logged in as {bot.user}')

이런식으로 봇이 준비되면 콘솔에 정보가 나타난다.
@bot.event
async def on_message(message):
메세지를 수신하는 함수다. 이제 여기 안에서 TTS를 재생시키는 코드를 집어 넣으면 된다.
# 메세지 발신자가 봇인 경우
if message.author.bot:
return
# 메세지 발신 채널이 원하는 채널이 아닌 경우
if message.channel.id != int(TEXT_CHANNEL_ID):
return
# 음성채널 연결 해제를 위한 타이머 전역변수
global disconnect_timer
메세지 발신자가 봇이거나 메세지 발신 채널이 원하는 채널이 아닌 경우 함수를 종료하도록 한다.
후자를 설정하는 이유는 모든 채널에 TTS를 적용했다가는 난장판이 일어날 게 뻔하기 때문에 TTS 전용 채널을 설정해두고 쓰는게 좋기 때문이다.
# 봇이 음성채널에 연결되어있지 않은 경우
if bot.voice_clients == []:
channel = bot.get_channel(int(VOICE_CHANNEL_ID))
await channel.connect()
# 현재 봇이 접속하고 있는 음성채널 정보
voice = bot.voice_clients[0]
# TTS 음성 생성
tts = NaverTTS(message.content, speed=0)
tts.save('tts.mp3')
현재 봇이 음성채널에 접속하고 있지 않다면 접속해준다. 그리고 접속했다면 해당 음성채널 정보를 따로 변수로 만들어준다.
NaverTTS로 TTS음원을 만들어준다. 여기서는 speed라는 옵션으로 속도를 조절할 수 있다. -5 ~ 5 사이 숫자로 지정해주면 되고, 숫자가 작을수록 빨라진다. 정수만 가능하니 소수점은 쓰지 말자.
그리고 굳이 mp3로 저장한 이유는 google-tts와는 다르게 NaverTTS는 바로 재생이 안된다. 아니면 가능한데 내가 방법을 못 찾은 것일 수도 있다.
아무튼 여기서는 파일로 저장하고 재생하는 방식을 사용할 것이다.
파일명을 지정해두면 새로운 파일을 만들 때마다 덮어쓰기때문에 용량이 무지막지하게 늘어날 염려는 없어도 되지 않을까
# 만약 음성 재생중이라면
if voice.is_playing():
voice.stop()
# TTS 재생하기
voice.play(discord.FFmpegPCMAudio('tts.mp3'))
만약 음성 재생중인데 메세지가 새로 올라온다면 재생하던걸 멈추고 새로운걸 재생한다. 이건 주관적이므로 중간에 끊는걸 원치 않으면 대기했다가 재생하는 방법을 택하면 된다.
그리고 TTS를 재생하기 위해서는 FFmpeg가 필요하다.
https://ffmpeg.org/download.html
FFmpeg는 상단 사이트에 들어가면 있는 압축파일 내 exe 파일들을 파이썬이 설치된 디렉토리에 넣어주면 된다.
# 새로운 메세지가 올라올 때마다 타이머 초기화
if disconnect_timer:
disconnect_timer.cancel()
disconnect_timer = asyncio.create_task(voice_disconnect_after_delay(7.0))
만약 disconnect_timer가 None이 아니라면 create_task를 취소한다.
밑에는 disconnect_timer에 일정 시간 딜레이 후 실행되는 함수를 설정해준다.
# 일정 시간 딜레이 후 voice_disconnect() 실행
async def voice_disconnect_after_delay(delay):
await asyncio.sleep(delay)
await voice_disconnect()
# 퇴장 인사 재생
async def voice_disconnect():
voice = bot.voice_clients[0]
# 음성채널에 연결되어있다면
if voice.is_connected():
tts = NaverTTS('저는 이만 가볼게요', speed=0)
tts.save('tts.mp3')
voice.play(discord.FFmpegPCMAudio('tts.mp3'))
time.sleep(3)
await voice.disconnect()
bot.run(BOT_TOKEN)
위와 같이 함수를 만들어주고 마지막에 bot을 실행시켜주면 된다.