334 lines
11 KiB
Python
334 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
번역 모듈 - 구글 번역 API를 사용한 중국어-한국어 번역
|
|
텍스트 전처리, 후처리, 캐싱 기능을 포함합니다.
|
|
"""
|
|
|
|
from googletrans import Translator
|
|
from translatepy.translators.google import GoogleTranslate
|
|
import re
|
|
import time
|
|
from typing import List, Dict, Any
|
|
import os
|
|
import random
|
|
|
|
class TranslationModule:
|
|
def __init__(self):
|
|
"""번역 모듈 초기화"""
|
|
print("번역 모듈 초기화 중...")
|
|
|
|
# 시뮬레이션 모드 기본 활성화
|
|
self.simulation_mode = True
|
|
|
|
# 번역 캐시 초기화
|
|
self.translation_cache = {}
|
|
|
|
# Google Translate 초기화 시도
|
|
try:
|
|
self.gtranslate = GoogleTranslate()
|
|
# self.translator = Translator()
|
|
print("Google Translate 초기화 완료")
|
|
except Exception as e:
|
|
print(f"Google Translate 초기화 실패: {e}")
|
|
print("시뮬레이션 모드로 동작합니다.")
|
|
self.gtranslate = None
|
|
|
|
print("번역 모듈 초기화 완료")
|
|
|
|
def translate_chinese_to_korean(self, original_name: str) -> str:
|
|
"""텍스트를 한국어로 번역하는 메서드"""
|
|
try:
|
|
translated_name = self.gtranslate.translate(original_name, 'ko')
|
|
# 만약 번역 결과가 None이거나 str이 아니면 원본 반환
|
|
if not isinstance(translated_name, str) or not translated_name:
|
|
return str(original_name)
|
|
return translated_name
|
|
except Exception as e:
|
|
return str(original_name)
|
|
|
|
|
|
# def translate_chinese_to_korean(self, text: str, retry_count: int = 3) -> str:
|
|
# """
|
|
# 중국어를 한국어로 번역
|
|
|
|
# Args:
|
|
# text (str): 번역할 중국어 텍스트
|
|
# retry_count (int): 재시도 횟수
|
|
|
|
# Returns:
|
|
# str: 번역된 한국어 텍스트
|
|
# """
|
|
# if not text or not text.strip():
|
|
# return text
|
|
|
|
|
|
# # 텍스트 전처리
|
|
# cleaned_text = self.preprocess_text(text)
|
|
|
|
# for attempt in range(retry_count):
|
|
# try:
|
|
# # 중국어 감지 및 번역 (동기 방식으로 수정)
|
|
# if self.is_chinese_text(cleaned_text):
|
|
# result = self.translator.translate(cleaned_text, src='zh', dest='ko')
|
|
# translated_text = result.text
|
|
|
|
# # 후처리
|
|
# processed_text = self.postprocess_text(translated_text)
|
|
|
|
# print(f"번역 완료: '{cleaned_text}' -> '{processed_text}'")
|
|
# return processed_text
|
|
# else:
|
|
# print(f"중국어가 아닌 텍스트로 판단됨")
|
|
# return text
|
|
|
|
# except Exception as e:
|
|
# print(f"번역 시도 {attempt + 1} 실패: {e}")
|
|
# if attempt < retry_count - 1:
|
|
# time.sleep(1) # 1초 대기 후 재시도
|
|
# else:
|
|
# print("번역 실패, 원본 텍스트 반환")
|
|
# return text
|
|
|
|
# return text
|
|
|
|
|
|
def translate_batch(self, texts: List[str], delay: float = 0.1) -> List[str]:
|
|
"""
|
|
여러 텍스트를 일괄 번역
|
|
|
|
Args:
|
|
texts (List[str]): 번역할 텍스트 리스트
|
|
delay (float): 각 번역 사이의 지연 시간 (초)
|
|
|
|
Returns:
|
|
List[str]: 번역된 텍스트 리스트
|
|
"""
|
|
translated_texts = []
|
|
|
|
for i, text in enumerate(texts):
|
|
print(f"번역 진행: {i+1}/{len(texts)}")
|
|
translated = self.translate_chinese_to_korean(text)
|
|
translated_texts.append(translated)
|
|
|
|
# API 호출 제한을 위한 지연
|
|
if delay > 0 and i < len(texts) - 1:
|
|
time.sleep(delay)
|
|
|
|
return translated_texts
|
|
|
|
def preprocess_text(self, text: str) -> str:
|
|
"""
|
|
번역 전 텍스트 전처리
|
|
|
|
Args:
|
|
text (str): 원본 텍스트
|
|
|
|
Returns:
|
|
str: 전처리된 텍스트
|
|
"""
|
|
# 불필요한 공백 제거
|
|
cleaned = re.sub(r'\s+', ' ', text.strip())
|
|
|
|
# 특수 문자 처리 (필요에 따라 조정)
|
|
# 예: 가격 표시 등은 그대로 유지
|
|
|
|
return cleaned
|
|
|
|
def postprocess_text(self, text: str) -> str:
|
|
"""
|
|
번역 후 텍스트 후처리
|
|
|
|
Args:
|
|
text (str): 번역된 텍스트
|
|
|
|
Returns:
|
|
str: 후처리된 텍스트
|
|
"""
|
|
# 불필요한 공백 제거
|
|
processed = re.sub(r'\s+', ' ', text.strip())
|
|
|
|
# 한국어 특성에 맞는 후처리
|
|
# 예: 숫자와 단위 사이 공백 조정
|
|
processed = re.sub(r'(\d+)\s+([가-힣]+)', r'\1\2', processed)
|
|
|
|
return processed
|
|
|
|
def detect_language(self, text: str) -> Dict[str, Any]:
|
|
"""
|
|
텍스트 언어 감지
|
|
|
|
Args:
|
|
text (str): 감지할 텍스트
|
|
|
|
Returns:
|
|
Dict: 언어 감지 결과
|
|
"""
|
|
if not self.translator:
|
|
return {'language': 'unknown', 'confidence': 0.0}
|
|
|
|
try:
|
|
detected = self.translator.detect(text)
|
|
return {
|
|
'language': detected.lang,
|
|
'confidence': detected.confidence
|
|
}
|
|
except Exception as e:
|
|
print(f"언어 감지 실패: {e}")
|
|
return {'language': 'unknown', 'confidence': 0.0}
|
|
|
|
def is_chinese_text(self, text: str) -> bool:
|
|
"""
|
|
텍스트가 중국어인지 확인
|
|
|
|
Args:
|
|
text (str): 확인할 텍스트
|
|
|
|
Returns:
|
|
bool: 중국어 여부
|
|
"""
|
|
# 유니코드 범위로 중국어 문자 확인
|
|
chinese_chars = 0
|
|
total_chars = 0
|
|
|
|
for char in text:
|
|
if char.isalpha():
|
|
total_chars += 1
|
|
if '\u4e00' <= char <= '\u9fff': # CJK 통합 한자
|
|
chinese_chars += 1
|
|
|
|
if total_chars == 0:
|
|
return False
|
|
|
|
# 중국어 문자 비율이 50% 이상이면 중국어로 판단
|
|
return (chinese_chars / total_chars) >= 0.5
|
|
|
|
def get_translation_confidence(self, original: str, translated: str) -> float:
|
|
"""
|
|
번역 품질 신뢰도 계산 (간단한 휴리스틱)
|
|
|
|
Args:
|
|
original (str): 원본 텍스트
|
|
translated (str): 번역된 텍스트
|
|
|
|
Returns:
|
|
float: 신뢰도 (0.0 ~ 1.0)
|
|
"""
|
|
# 기본 신뢰도
|
|
confidence = 0.8
|
|
|
|
# 길이 비율 확인
|
|
len_ratio = len(translated) / max(len(original), 1)
|
|
if len_ratio < 0.3 or len_ratio > 3.0:
|
|
confidence -= 0.2
|
|
|
|
# 번역 결과가 원본과 동일한 경우 (번역 실패 가능성)
|
|
if original == translated:
|
|
confidence -= 0.3
|
|
|
|
# 번역 결과에 중국어가 남아있는 경우
|
|
if self.is_chinese_text(translated):
|
|
confidence -= 0.4
|
|
|
|
return max(0.0, min(1.0, confidence))
|
|
|
|
def create_translation_cache(self) -> Dict[str, str]:
|
|
"""번역 캐시 생성 (자주 사용되는 단어들)"""
|
|
common_translations = {
|
|
# 상품 관련
|
|
'价格': '가격',
|
|
'优惠': '할인',
|
|
'折扣': '할인',
|
|
'免费': '무료',
|
|
'包邮': '무료배송',
|
|
'新品': '신상품',
|
|
'热销': '인기상품',
|
|
'限时': '한정시간',
|
|
'抢购': '특가',
|
|
'秒杀': '타임세일',
|
|
|
|
# 크기/색상 관련
|
|
'大号': '대형',
|
|
'中号': '중형',
|
|
'小号': '소형',
|
|
'颜色': '색상',
|
|
'尺寸': '사이즈',
|
|
'规格': '규격',
|
|
|
|
# 품질 관련
|
|
'高品质': '고품질',
|
|
'优质': '우수한 품질',
|
|
'精品': '정품',
|
|
'原装': '정품',
|
|
'正品': '정품',
|
|
}
|
|
|
|
return common_translations
|
|
|
|
def translate_with_cache(self, text: str) -> str:
|
|
"""
|
|
캐시를 사용한 번역 (빠른 번역을 위해)
|
|
|
|
Args:
|
|
text (str): 번역할 텍스트
|
|
|
|
Returns:
|
|
str: 번역된 텍스트
|
|
"""
|
|
cache = self.create_translation_cache()
|
|
|
|
# 캐시에서 정확히 일치하는 항목 찾기
|
|
if text in cache:
|
|
print(f"캐시에서 번역: '{text}' -> '{cache[text]}'")
|
|
return cache[text]
|
|
|
|
# 캐시에 없으면 일반 번역
|
|
return self.translate_chinese_to_korean(text)
|
|
|
|
def test_module(self):
|
|
"""번역 모듈 테스트"""
|
|
print("번역 모듈 테스트 시작...")
|
|
|
|
# 테스트 중국어 텍스트들
|
|
test_texts = [
|
|
"你好",
|
|
"谢谢",
|
|
"价格优惠",
|
|
"免费包邮",
|
|
"高品质商品",
|
|
"限时抢购",
|
|
"新品上市",
|
|
"折扣价格",
|
|
"大号尺寸",
|
|
"正品保证"
|
|
]
|
|
|
|
print("개별 번역 테스트:")
|
|
for text in test_texts:
|
|
# 언어 감지
|
|
lang_info = self.detect_language(text)
|
|
print(f"'{text}' - 언어: {lang_info['language']}, 신뢰도: {lang_info['confidence']:.2f}")
|
|
|
|
# 번역
|
|
translated = self.translate_chinese_to_korean(text)
|
|
|
|
# 번역 신뢰도
|
|
confidence = self.get_translation_confidence(text, translated)
|
|
print(f"번역 신뢰도: {confidence:.2f}")
|
|
print()
|
|
|
|
print("일괄 번역 테스트:")
|
|
batch_results = self.translate_batch(test_texts[:5])
|
|
for original, translated in zip(test_texts[:5], batch_results):
|
|
print(f"'{original}' -> '{translated}'")
|
|
|
|
print("캐시 번역 테스트:")
|
|
cache_test_texts = ["价格", "优惠", "免费", "新品"]
|
|
for text in cache_test_texts:
|
|
cached_result = self.translate_with_cache(text)
|
|
print(f"'{text}' -> '{cached_result}'")
|
|
|
|
print("번역 모듈 테스트 완료!")
|
|
|
|
if __name__ == "__main__":
|
|
translator = TranslationModule()
|
|
translator.test_module() |