AutoPercenty3/test/xai/test_openrouter.py

476 lines
15 KiB
Python

# -*- coding: utf-8 -*-
"""
OpenRouter 클라이언트 테스트 모듈
다양한 모델을 순차적으로 테스트하여 응답 품질과 속도를 비교합니다.
사용법:
python test_openrouter.py
python test_openrouter.py --models gemini-2.5-flash,gpt-4o-mini
python test_openrouter.py --test ocr
python test_openrouter.py --test all
"""
from __future__ import annotations
import os
import sys
import time
import json
import argparse
import logging
from typing import List, Dict, Any, Optional
from datetime import datetime
# 상위 디렉토리 경로 추가
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
try:
from src.titleManager.openrouter_client import OpenRouterTranslator, OpenRouterError
except ImportError:
# 직접 실행 시 경로 조정
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "src", "titleManager"))
from openrouter_client import OpenRouterTranslator, OpenRouterError
# 로깅 설정
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%H:%M:%S"
)
logger = logging.getLogger(__name__)
# ============================================================
# 테스트 데이터
# ============================================================
# OCR 번역 테스트 데이터
OCR_TEST_DATA = {
"product_name": "휴대용 미니 선풍기",
"category": "가전/계절가전/선풍기",
"ocr_results": [
{"text": "强力送风"},
{"text": "USB-C 快速充电"},
{"text": "3档风速调节"},
{"text": "超静音设计"},
{"text": "长续航8小时"},
{"text": "便携式设计"},
]
}
# 상품 분석 테스트 데이터
PRODUCT_ANALYSIS_TEST_DATA = [
"삼성전자 갤럭시북4 프로 360 NT960QGK-K71A 16인치 인텔 코어 울트라7 터치스크린 문스톤 그레이",
"Apple 맥북 프로 14인치 M3 Pro 칩 18GB 512GB 스페이스 블랙 MRX33KH/A",
"LG전자 그램 17ZD90S-GX56K 17인치 인텔 코어 울트라5 16GB 256GB 화이트",
]
# 옵션 번역 테스트 데이터
OPTION_TEST_DATA = {
"product_name": "무선 블루투스 이어폰",
"category": "디지털/음향기기/이어폰",
"option_groups": [
{"id": 1, "source": ["白色", "黑色", "粉色", "蓝色"]},
{"id": 2, "source": ["标准版", "升级版", "豪华版"]},
{"id": 3, "source": ["单耳", "双耳", "双耳+充电仓"]},
]
}
# 상품명 생성 테스트 데이터
PRODUCT_NAME_TEST_DATA = {
"original_name": "无线蓝牙耳机降噪入耳式运动跑步超长续航",
"keywords": ["무선이어폰", "블루투스", "노이즈캔슬링", "운동용", "방수"],
"category": "디지털/음향기기/이어폰",
"top_titles": [
"삼성 갤럭시버즈3 프로 무선 블루투스 이어폰 노이즈캔슬링",
"애플 에어팟 프로 2세대 무선 이어폰 액티브 노이즈 캔슬링",
"소니 WF-1000XM5 무선 이어폰 노캔 하이레졸루션",
]
}
# 테스트할 모델 목록 (저렴한 것부터)
TEST_MODELS = [
# 무료/저렴한 모델
"gemini-flash-free",
"gemini-2.0-flash",
"gemini-2.5-flash",
# 중간 가격대
"gpt-4o-mini",
"claude-3-haiku",
"deepseek-chat",
"llama-3.3-70b",
# 고가 모델 (선택적)
# "gpt-4o",
# "claude-3.5-sonnet",
]
# ============================================================
# 테스트 함수들
# ============================================================
def test_health_check(client: OpenRouterTranslator) -> Dict[str, Any]:
"""API 연결 상태 테스트"""
start = time.time()
try:
result = client.health_check()
elapsed = time.time() - start
return {
"success": result,
"elapsed": elapsed,
"message": "OK" if result else "Failed"
}
except Exception as e:
return {
"success": False,
"elapsed": time.time() - start,
"message": str(e)
}
def test_ocr_translation(client: OpenRouterTranslator) -> Dict[str, Any]:
"""OCR 번역 테스트"""
start = time.time()
try:
results = client.translate_ocr_texts(
product_name=OCR_TEST_DATA["product_name"],
category=OCR_TEST_DATA["category"],
ocr_results=OCR_TEST_DATA["ocr_results"]
)
elapsed = time.time() - start
# 결과 검증
success = len(results) == len(OCR_TEST_DATA["ocr_results"])
non_empty = sum(1 for r in results if r.strip())
return {
"success": success and non_empty > 0,
"elapsed": elapsed,
"input_count": len(OCR_TEST_DATA["ocr_results"]),
"output_count": len(results),
"non_empty_count": non_empty,
"results": results
}
except Exception as e:
return {
"success": False,
"elapsed": time.time() - start,
"message": str(e)
}
def test_product_analysis(client: OpenRouterTranslator) -> Dict[str, Any]:
"""상품 분석 테스트"""
start = time.time()
try:
test_text = PRODUCT_ANALYSIS_TEST_DATA[0]
result = client.analyze_product_info(test_text)
elapsed = time.time() - start
# 결과 검증
has_brand = "브랜드" in result or "brand" in str(result).lower()
has_name = "상품명" in result or "product" in str(result).lower()
return {
"success": has_brand or has_name,
"elapsed": elapsed,
"input": test_text,
"result": result
}
except Exception as e:
return {
"success": False,
"elapsed": time.time() - start,
"message": str(e)
}
def test_option_translation(client: OpenRouterTranslator) -> Dict[str, Any]:
"""옵션 번역 테스트"""
start = time.time()
try:
results = client.translate_option_groups(
product_name=OPTION_TEST_DATA["product_name"],
category=OPTION_TEST_DATA["category"],
option_groups=OPTION_TEST_DATA["option_groups"]
)
elapsed = time.time() - start
# 결과 검증
success = len(results) == len(OPTION_TEST_DATA["option_groups"])
return {
"success": success,
"elapsed": elapsed,
"input_count": len(OPTION_TEST_DATA["option_groups"]),
"output_count": len(results),
"results": results
}
except Exception as e:
return {
"success": False,
"elapsed": time.time() - start,
"message": str(e)
}
def test_product_name_generation(client: OpenRouterTranslator) -> Dict[str, Any]:
"""상품명 생성 테스트"""
start = time.time()
try:
result = client.generate_product_name(
original_name=PRODUCT_NAME_TEST_DATA["original_name"],
keywords=PRODUCT_NAME_TEST_DATA["keywords"],
category=PRODUCT_NAME_TEST_DATA["category"],
top_titles=PRODUCT_NAME_TEST_DATA["top_titles"]
)
elapsed = time.time() - start
# 결과 검증
success = bool(result) and len(result) >= 20
return {
"success": success,
"elapsed": elapsed,
"result": result,
"length": len(result) if result else 0
}
except Exception as e:
return {
"success": False,
"elapsed": time.time() - start,
"message": str(e)
}
def test_simple_chat(client: OpenRouterTranslator) -> Dict[str, Any]:
"""간단한 채팅 테스트"""
start = time.time()
try:
result = client.ask_text(
"한국의 수도는 어디인가요? 한 단어로만 답하세요.",
system_prompt="짧고 간결하게 답변하세요."
)
elapsed = time.time() - start
# 결과 검증 (서울이 포함되어야 함)
success = "서울" in result
return {
"success": success,
"elapsed": elapsed,
"result": result
}
except Exception as e:
return {
"success": False,
"elapsed": time.time() - start,
"message": str(e)
}
# ============================================================
# 메인 테스트 러너
# ============================================================
def run_tests(
api_key: str,
models: List[str],
test_types: List[str],
verbose: bool = True
) -> Dict[str, Any]:
"""
여러 모델에 대해 테스트 실행
Args:
api_key: OpenRouter API 키
models: 테스트할 모델 리스트
test_types: 테스트 유형 리스트 (health, chat, ocr, analysis, option, name, all)
verbose: 상세 출력 여부
Returns:
dict: 테스트 결과
"""
all_results = {}
# 테스트 함수 매핑
test_functions = {
"health": ("Health Check", test_health_check),
"chat": ("Simple Chat", test_simple_chat),
"ocr": ("OCR Translation", test_ocr_translation),
"analysis": ("Product Analysis", test_product_analysis),
"option": ("Option Translation", test_option_translation),
"name": ("Product Name Generation", test_product_name_generation),
}
# "all" 처리
if "all" in test_types:
test_types = list(test_functions.keys())
print("\n" + "=" * 70)
print(f"OpenRouter 모델 테스트 시작")
print(f"테스트 시간: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"테스트 모델: {', '.join(models)}")
print(f"테스트 항목: {', '.join(test_types)}")
print("=" * 70 + "\n")
for model in models:
print(f"\n{'' * 50}")
print(f"📦 모델: {model}")
print(f"{'' * 50}")
model_results = {}
try:
# 클라이언트 생성
client = OpenRouterTranslator(
api_key=api_key,
model=model,
temperature=0.1,
logger=logger
)
model_info = client.get_model_info()
print(f" 모델 ID: {model_info['model_id']}")
print(f" 가격: 입력 ${model_info['pricing'].get('input', 'N/A')}/1M, 출력 ${model_info['pricing'].get('output', 'N/A')}/1M")
print()
# 각 테스트 실행
for test_key in test_types:
if test_key not in test_functions:
continue
test_name, test_func = test_functions[test_key]
print(f" 🔍 {test_name}...", end=" ", flush=True)
result = test_func(client)
model_results[test_key] = result
if result["success"]:
print(f"✅ ({result['elapsed']:.2f}s)")
if verbose and "result" in result:
if isinstance(result["result"], str):
print(f"{result['result'][:100]}...")
elif isinstance(result["result"], list):
print(f"{result['result'][:3]}...")
elif isinstance(result["result"], dict):
print(f"{json.dumps(result['result'], ensure_ascii=False)[:100]}...")
else:
print(f"❌ ({result.get('message', 'Unknown error')})")
except OpenRouterError as e:
print(f" ❌ 클라이언트 초기화 실패: {e}")
model_results["error"] = str(e)
except Exception as e:
print(f" ❌ 예상치 못한 오류: {e}")
model_results["error"] = str(e)
all_results[model] = model_results
# 결과 요약
print("\n" + "=" * 70)
print("📊 테스트 결과 요약")
print("=" * 70)
# 테이블 헤더
header = ["모델"] + [test_functions[t][0] for t in test_types if t in test_functions]
print(f"\n{'모델':<25}", end="")
for test_key in test_types:
if test_key in test_functions:
print(f"{test_functions[test_key][0]:<20}", end="")
print()
print("-" * (25 + 20 * len([t for t in test_types if t in test_functions])))
for model, results in all_results.items():
print(f"{model:<25}", end="")
for test_key in test_types:
if test_key in test_functions:
if test_key in results:
status = "" if results[test_key]["success"] else ""
elapsed = f"({results[test_key]['elapsed']:.1f}s)"
print(f"{status} {elapsed:<16}", end="")
else:
print(f"{'':<20}", end="")
print()
print("\n" + "=" * 70 + "\n")
return all_results
def main():
parser = argparse.ArgumentParser(description="OpenRouter 클라이언트 테스트")
parser.add_argument(
"--api-key",
type=str,
default=os.getenv("OPENROUTER_API_KEY"),
help="OpenRouter API 키 (환경변수 OPENROUTER_API_KEY로도 설정 가능)"
)
parser.add_argument(
"--models",
type=str,
default=None,
help="테스트할 모델 (쉼표로 구분, 예: gemini-2.5-flash,gpt-4o-mini)"
)
parser.add_argument(
"--test",
type=str,
default="all",
help="테스트 유형 (health,chat,ocr,analysis,option,name,all)"
)
parser.add_argument(
"--verbose", "-v",
action="store_true",
help="상세 출력"
)
parser.add_argument(
"--list-models",
action="store_true",
help="사용 가능한 모델 목록 출력"
)
args = parser.parse_args()
# 모델 목록 출력
if args.list_models:
print("\n사용 가능한 모델 목록:")
print("-" * 50)
for alias, model_id in OpenRouterTranslator.MODEL_MAP.items():
pricing = OpenRouterTranslator.MODEL_PRICING.get(model_id, {})
price_str = f"${pricing.get('input', '?')}/{pricing.get('output', '?')}" if pricing else "가격 미정"
print(f" {alias:<25}{model_id}")
print()
return
# API 키 확인
if not args.api_key:
print("❌ API 키가 필요합니다.")
print(" --api-key 옵션을 사용하거나 OPENROUTER_API_KEY 환경변수를 설정하세요.")
sys.exit(1)
# 모델 목록 파싱
if args.models:
models = [m.strip() for m in args.models.split(",")]
else:
models = TEST_MODELS
# 테스트 유형 파싱
test_types = [t.strip() for t in args.test.split(",")]
# 테스트 실행
run_tests(
api_key=args.api_key,
models=models,
test_types=test_types,
verbose=args.verbose
)
if __name__ == "__main__":
main()