inpaintServer/tests/scripts/test_api.py

314 lines
12 KiB
Python

#!/usr/bin/env python3
"""
API 테스트 스크립트 (iopaint 호환성 중심)
각 엔드포인트가 iopaint와 호환되는지 테스트합니다.
"""
import os
import sys
import base64
import time
import requests
import json
from pathlib import Path
# 프로젝트 루트를 Python 경로에 추가
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, project_root)
class IopaintAPITester:
def __init__(self, base_url="http://localhost:8008"):
self.base_url = base_url
self.test_images_dir = os.path.join(project_root, "tests", "images")
self.results_dir = os.path.join(project_root, "tests", "results")
# 결과 디렉토리 생성
os.makedirs(self.results_dir, exist_ok=True)
print(f"🚀 iopaint 호환성 API 테스터 초기화 완료")
print(f" 서버 URL: {base_url}")
print(f" 테스트 이미지: {self.test_images_dir}")
print(f" 결과 저장: {self.results_dir}")
def image_to_base64(self, image_path):
"""이미지를 base64로 인코딩 (iopaint 호환)"""
try:
with open(image_path, "rb") as image_file:
encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
return encoded_string
except Exception as e:
print(f"❌ 이미지 인코딩 실패: {e}")
return None
def save_base64_image(self, base64_string, filename):
"""base64 이미지를 파일로 저장"""
try:
image_data = base64.b64decode(base64_string)
filepath = os.path.join(self.results_dir, filename)
with open(filepath, "wb") as f:
f.write(image_data)
print(f" 💾 결과 이미지 저장: {filename}")
return True
except Exception as e:
print(f"❌ 이미지 저장 실패: {e}")
return False
def test_health(self):
"""헬스 체크 테스트 (iopaint 호환)"""
print("\n🏥 헬스 체크 테스트...")
try:
response = requests.get(f"{self.base_url}/health", timeout=10)
if response.status_code == 200:
data = response.json()
print(f" ✅ 서버 상태: {data.get('status', 'unknown')}")
print(f" 📊 가동 시간: {data.get('uptime', 0):.2f}")
return True
else:
print(f" ❌ 서버 응답 실패: {response.status_code}")
return False
except Exception as e:
print(f" ❌ 연결 실패: {e}")
return False
def test_server_config(self):
"""서버 설정 정보 테스트 (iopaint 호환)"""
print("\n⚙️ 서버 설정 정보 테스트...")
try:
response = requests.get(f"{self.base_url}/api/v1/server-config", timeout=10)
if response.status_code == 200:
data = response.json()
print(f" ✅ 서버 설정 조회 성공")
print(f" 🖥️ 시스템: {'Jetson Xavier' if data.get('is_jetson') else 'x86_64'}")
print(f" 🎮 디바이스: {data.get('device', 'unknown')}")
print(f" 📁 최대 파일 크기: {data.get('max_file_size', 0)}MB")
print(f" 🎯 사용 가능한 모델: {len(data.get('models', []))}")
return True
else:
print(f" ❌ 서버 설정 조회 실패: {response.status_code}")
return False
except Exception as e:
print(f" ❌ 연결 실패: {e}")
return False
def test_inpaint(self, image_name="test_image_512.png", mask_name="test_mask_512.png"):
"""인페인팅 API 테스트 (iopaint 호환)"""
print(f"\n🎨 인페인팅 테스트 ({image_name} + {mask_name})...")
# 이미지 파일 경로
image_path = os.path.join(self.test_images_dir, image_name)
mask_path = os.path.join(self.test_images_dir, mask_name)
if not os.path.exists(image_path) or not os.path.exists(mask_path):
print(f" ❌ 테스트 이미지 파일이 없습니다")
return False
try:
# 이미지를 base64로 인코딩 (iopaint 형식)
image_base64 = self.image_to_base64(image_path)
mask_base64 = self.image_to_base64(mask_path)
if not image_base64 or not mask_base64:
return False
# 인페인팅 요청 (iopaint 호환 형식)
payload = {
"image": image_base64,
"mask": mask_base64,
"model_name": "simple-lama",
"sd_seed": 42,
"prompt": "beautiful landscape",
"negative_prompt": "ugly, blurry",
"num_inference_steps": 20,
"guidance_scale": 7.5,
"strength": 1.0
}
start_time = time.time()
response = requests.post(
f"{self.base_url}/api/v1/inpaint",
json=payload,
timeout=60
)
processing_time = time.time() - start_time
if response.status_code == 200:
data = response.json()
print(f" ✅ 인페인팅 성공!")
print(f" ⏱️ 처리 시간: {data.get('processing_time', processing_time):.2f}")
print(f" 🎲 사용된 시드: {data.get('seed', 'unknown')}")
# 결과 이미지 저장
if data.get('image'):
self.save_base64_image(data['image'], f"inpaint_result_{image_name}")
return True
else:
print(f" ❌ 인페인팅 실패: {response.status_code}")
try:
error_data = response.json()
print(f" 📝 에러 메시지: {error_data.get('detail', 'unknown error')}")
except:
print(f" 📝 응답 내용: {response.text}")
return False
except Exception as e:
print(f" ❌ 인페인팅 테스트 실패: {e}")
return False
def test_remove_bg(self, image_name="test_image_512.png"):
"""배경 제거 API 테스트 (iopaint 호환)"""
print(f"\n🖼️ 배경 제거 테스트 ({image_name})...")
# 이미지 파일 경로
image_path = os.path.join(self.test_images_dir, image_name)
if not os.path.exists(image_path):
print(f" ❌ 테스트 이미지 파일이 없습니다")
return False
try:
# 이미지를 base64로 인코딩 (iopaint 형식)
image_base64 = self.image_to_base64(image_path)
if not image_base64:
return False
# 배경 제거 요청 (iopaint 호환 형식)
payload = {
"image": image_base64,
"model_name": "rembg"
}
start_time = time.time()
response = requests.post(
f"{self.base_url}/api/v1/remove_bg",
json=payload,
timeout=60
)
processing_time = time.time() - start_time
if response.status_code == 200:
data = response.json()
print(f" ✅ 배경 제거 성공!")
print(f" ⏱️ 처리 시간: {data.get('processing_time', processing_time):.2f}")
# 결과 이미지와 마스크 저장
if data.get('image'):
self.save_base64_image(data['image'], f"rembg_result_{image_name}")
if data.get('mask'):
self.save_base64_image(data['mask'], f"rembg_mask_{image_name}")
return True
else:
print(f" ❌ 배경 제거 실패: {response.status_code}")
try:
error_data = response.json()
print(f" 📝 에러 메시지: {error_data.get('detail', 'unknown error')}")
except:
print(f" 📝 응답 내용: {response.text}")
return False
except Exception as e:
print(f" ❌ 배경 제거 테스트 실패: {e}")
return False
def test_samplers(self):
"""샘플러 목록 테스트 (iopaint 호환)"""
print("\n🎲 샘플러 목록 테스트...")
try:
response = requests.get(f"{self.base_url}/api/v1/samplers", timeout=10)
if response.status_code == 200:
samplers = response.json()
print(f" ✅ 샘플러 목록 조회 성공")
print(f" 📊 사용 가능한 샘플러: {len(samplers)}")
print(f" 🎯 샘플러들: {', '.join(samplers[:5])}{'...' if len(samplers) > 5 else ''}")
return True
else:
print(f" ❌ 샘플러 목록 조회 실패: {response.status_code}")
return False
except Exception as e:
print(f" ❌ 연결 실패: {e}")
return False
def run_all_tests(self):
"""모든 iopaint 호환성 테스트 실행"""
print("🧪 iopaint 호환성 API 테스트 시작")
print("=" * 60)
test_results = []
# 1. 헬스 체크
test_results.append(("헬스 체크", self.test_health()))
# 2. 서버 설정 정보
test_results.append(("서버 설정 정보", self.test_server_config()))
# 3. 샘플러 목록
test_results.append(("샘플러 목록", self.test_samplers()))
# 4. 인페인팅 테스트 (작은 이미지)
test_results.append(("인페인팅 (256x256)", self.test_inpaint("test_image_256.png", "test_mask_256.png")))
# 5. 인페인팅 테스트 (기본 이미지)
test_results.append(("인페인팅 (512x512)", self.test_inpaint("test_image_512.png", "test_mask_512.png")))
# 6. 배경 제거 테스트
test_results.append(("배경 제거", self.test_remove_bg("test_image_512.png")))
# 결과 요약
print("\n" + "=" * 60)
print("📊 iopaint 호환성 테스트 결과 요약")
print("=" * 60)
passed = 0
total = len(test_results)
for test_name, result in test_results:
status = "✅ PASS" if result else "❌ FAIL"
print(f"{test_name:<30} {status}")
if result:
passed += 1
print("=" * 60)
print(f"전체: {total}개, 성공: {passed}개, 실패: {total - passed}")
if passed == total:
print("🎉 모든 iopaint 호환성 테스트가 성공했습니다!")
print(" 클라이언트 코드 수정 없이 기존 iopaint와 연동 가능합니다!")
else:
print("⚠️ 일부 테스트가 실패했습니다.")
print(" iopaint 호환성을 위해 추가 수정이 필요합니다.")
return passed == total
def main():
"""메인 함수"""
import argparse
parser = argparse.ArgumentParser(description="iopaint 호환성 API 테스트 스크립트")
parser.add_argument("--url", default="http://localhost:8008", help="테스트할 서버 URL")
parser.add_argument("--single", help="단일 테스트 실행 (health, config, inpaint, rembg)")
args = parser.parse_args()
tester = IopaintAPITester(args.url)
if args.single:
# 단일 테스트 실행
if args.single == "health":
tester.test_health()
elif args.single == "config":
tester.test_server_config()
elif args.single == "inpaint":
tester.test_inpaint()
elif args.single == "rembg":
tester.test_remove_bg()
else:
print(f"❌ 알 수 없는 테스트: {args.single}")
else:
# 전체 테스트 실행
tester.run_all_tests()
if __name__ == "__main__":
main()