PyQt5, Hugging Face Transformers, Eleven Labs API 활용
- 영어 → 한국어 자동 번역
- 번역된 텍스트 → 음성 변환
- 변환된 음성 → 재생
- GUI 인터페이스 제공
번역 | 영어 문장을 입력하면 NLLB-200 모델로 한국어로 번역 |
음성 생성 | 번역된 문장을 Eleven Labs API로 음성(mp3)으로 변환 |
음성 재생 | 생성된 mp3 파일을 PyDub으로 재생 |
GUI 구성 | PyQt5로 사용자 인터페이스 구성 (입력, 버튼, 출력 등) |
pip install requests PyQt5 pydub dotenv transformers torch torchaudio torchmedia
필요 라이브러리
import os
import requests
from dotenv import load_dotenv
from PyQt5 import QtWidgets
from PyQt5.QtCore import QUrl
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
from pydub import AudioSegment
from pydub.playback import play
import io
PyQt5: GUI 및 재생 인터페이스
transformers: Facebook의 NLLB 번역 모델 사용
pydub: 생성된 mp3 음성 재생
requests, dotenv: Eleven Labs API 호출, 환경변수 로딩
클래스 구조
TranslatorApp 클래스
class TranslatorApp(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.init_ui()
# 번역 모델 로딩
model_name = "facebook/nllb-200-distilled-600M"
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
# API 설정 로드
load_dotenv()
self.api_key = os.getenv("API_KEY")
self.url = os.getenv("API_URL")
self.player = QMediaPlayer()
모델: facebook/nllb-200-distilled-600M (NLLB-200 경량 모델)
API 키와 URL: .env에서 불러옴
음성 재생기: QMediaPlayer 초기화
UI 구성 (init_ui)
def init_ui(self):
self.text_input = QtWidgets.QLineEdit(self)
self.text_input.setPlaceholderText("번역할 텍스트 입력")
self.translate_button = QtWidgets.QPushButton("번역 및 음성 생성", self)
self.output_label = QtWidgets.QLabel(self)
self.play_button = QtWidgets.QPushButton("음성 재생", self)
self.play_button.setEnabled(False)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.text_input)
layout.addWidget(self.translate_button)
layout.addWidget(self.output_label)
layout.addWidget(self.play_button)
self.setLayout(layout)
self.translate_button.clicked.connect(self.translate_and_generate_audio)
self.play_button.clicked.connect(self.play_audio)
self.setWindowTitle("번역 및 음성 생성기")
self.show()
입력 필드 + 버튼 + 번역 결과 출력 + 음성 재생 버튼 구성
translate_button → 번역 및 음성 생성
play_button → 생성된 음성 파일 재생
번역 및 음성 생성 기능
def translate_and_generate_audio(self):
text = self.text_input.text()
# 번역 수행
inputs = self.tokenizer(text, return_tensors="pt")
generated_tokens = self.model.generate(
inputs.input_ids,
forced_bos_token_id=self.tokenizer.lang_code_to_id["kor_Hang"]
)
translated_text = self.tokenizer.decode(generated_tokens[0], skip_special_tokens=True)
# Eleven Labs 음성 생성 요청
data = {
"text": translated_text,
"model_id": "eleven_multilingual_v2",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 1,
"style": 0.5,
"use_speaker_boost": True
}
}
headers = {
"xi-api-key": self.api_key,
"Content-Type": "application/json"
}
response = requests.post(self.url, json=data, headers=headers)
if response.status_code == 200:
output_audio_path = "audio_output/output_audio.mp3"
with open(output_audio_path, "wb") as f:
f.write(response.content)
self.output_label.setText(f"번역 결과: {translated_text}")
self.play_button.setEnabled(True)
else:
self.output_label.setText("음성 생성 실패")
NLLB 모델로 번역
Eleven Labs API로 mp3 음성 생성
성공 시 mp3 저장 + 결과 출력
음성 재생 기능
def play_audio(self):
audio_path = "audio_output/output_audio.mp3"
if os.path.exists(audio_path):
audio = AudioSegment.from_mp3(audio_path)
play(audio)
else:
self.output_label.setText("오디오 파일을 찾을 수 없습니다.")
pydub으로 mp3 로드 → 재생
파일 없으면 에러 메시지 출력
메인 실행부
if __name__ == '__main__':
app = QtWidgets.QApplication([])
translator = TranslatorApp()
app.exec_()
QApplication 생성
TranslatorApp 실행
GUI 이벤트 루프 시작
코드 조각을 활용한 전체 코드
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"
import requests
from dotenv import load_dotenv
from PyQt5 import QtWidgets
from transformers import AutoTokenizer
from PyQt5.QtCore import QUrl
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from transformers import AutoModelForSeq2SeqLM
from pydub import AudioSegment
class TranslatorApp(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.init_ui()
# 번역 모델 로드
model_name = "facebook/nllb-200-distilled-600M"
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
# 언어 코드 매핑
self.lang_map = {
"영어": "eng_Latn",
"한국어": "kor_Hang",
"불어": "fra_Latn",
"일본어": "jpn_Jpan",
"중국어": "zho_Hans",
}
# API 설정
load_dotenv()
self.api_key = os.getenv("ELEVENLABS_API_KEY")
self.api_url = os.getenv(
"API_URL"
) # e.g., https://api.elevenlabs.io/v1/text-to-speech/{voice_id}
# 음성 재생기
self.player = QMediaPlayer()
def init_ui(self):
# 입력 텍스트
self.text_input = QtWidgets.QLineEdit(self)
self.text_input.setPlaceholderText("번역할 텍스트 입력")
# 입력/출력 언어 선택 드롭다운
self.input_lang = QtWidgets.QComboBox(self)
self.input_lang.addItems(["영어", "한국어", "불어", "일본어", "중국어"])
self.output_lang = QtWidgets.QComboBox(self)
self.output_lang.addItems(["영어", "한국어", "불어", "일본어", "중국어"])
# 번역 버튼
self.translate_button = QtWidgets.QPushButton("번역 및 음성 생성", self)
self.output_label = QtWidgets.QLabel(self)
# 레이아웃 설정
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.text_input)
layout.addWidget(QtWidgets.QLabel("입력 언어"))
layout.addWidget(self.input_lang)
layout.addWidget(QtWidgets.QLabel("출력 언어"))
layout.addWidget(self.output_lang)
layout.addWidget(self.translate_button)
layout.addWidget(self.output_label)
self.setLayout(layout)
# 이벤트 핸들링
self.translate_button.clicked.connect(self.translate_and_generate_audio)
# 창 설정
self.setWindowTitle("다국어 번역 및 음성 생성기")
self.resize(400, 200)
self.show()
def translate_and_generate_audio(self):
text = self.text_input.text()
if not text:
self.output_label.setText("입력 텍스트를 작성해주세요.")
return
source_lang_code = self.lang_map[self.input_lang.currentText()]
target_lang_code = self.lang_map[self.output_lang.currentText()]
translated_text = ""
# 입력에 언어 prefix 붙이기
try:
print("Source Language Code:", source_lang_code)
self.tokenizer.src_lang = source_lang_code
batch = self.tokenizer(text, return_tensors="pt")
print("Input IDs:", batch["input_ids"])
print("Attention Mask:", batch["attention_mask"])
print("Target Language Code:", target_lang_code)
forced_bos_token_id = self.tokenizer.convert_tokens_to_ids(target_lang_code)
generated_tokens = self.model.generate(
input_ids=batch["input_ids"],
attention_mask=batch["attention_mask"],
forced_bos_token_id=forced_bos_token_id,
max_new_tokens=100,
)
translated_text = self.tokenizer.batch_decode(
generated_tokens, skip_special_tokens=True
)[0]
print("Generated Tokens:", generated_tokens)
print("Translated:", translated_text)
self.output_label.setText(f"번역 결과: {translated_text}")
except Exception as e:
print("Translation error:", str(e))
self.output_label.setText(f"번역 실패: {str(e)}")
# 음성 생성
data = {
"text": translated_text,
"model_id": "eleven_multilingual_v2",
"voice_settings": {"stability": 0.5, "similarity_boost": 0.5},
}
headers = {"xi-api-key": self.api_key, "Content-Type": "application/json"}
response = requests.post(self.api_url, json=data, headers=headers)
if response.status_code == 200:
output_audio_path = "audio_output/output_audio.mp3"
os.makedirs(os.path.dirname(output_audio_path), exist_ok=True)
with open(output_audio_path, "wb") as f:
f.write(response.content)
# mp3 → wav 변환 후 재생 (PyQt용)
sound = AudioSegment.from_mp3(output_audio_path)
wav_path = "audio_output/output_audio.wav"
sound.export(wav_path, format="wav")
audio_url = QUrl.fromLocalFile(os.path.abspath(wav_path))
self.player.setMedia(QMediaContent(audio_url))
self.player.play()
else:
self.output_label.setText(
f"음성 생성 실패\n{response.status_code} - {response.text}"
)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
translator = TranslatorApp()
app.exec_()
→ 입력언어와 출력언어를 다섯개로 늘리고, 사용자가 지정할 수 있도록 변경
→ 번역과 동시에 음성 생성
'⊢ AI 모델 활용' 카테고리의 다른 글
ChatGPT, FastAPI 활용 챗 서비스 구현 (0) | 2025.03.27 |
---|---|
OpenCV, YOLOv8, PyQt5활용 실시간 객체 탐지 서비스 구현 (1) | 2025.03.27 |
FastAI: 사전 학습된 모델을 활용한 이미지 분류 (4) | 2025.03.27 |
Ultralytics YOLOv8를 활용한 이미지 및 실시간 객체 탐지 (1) | 2025.03.26 |
ChatGPT와 ElevenLabs실습: 텍스트에서 음성까지 (2) | 2025.03.26 |