fix korean prompt logging at mcp-server-imagen4.log

This commit is contained in:
2025-08-24 01:01:01 +09:00
parent dcf2305e4b
commit 5b0ac22108
6 changed files with 349 additions and 66 deletions

8
.gitignore vendored
View File

@@ -116,4 +116,10 @@ generated_images/
# 임시 파일들 # 임시 파일들
temp_* temp_*
cleanup* cleanup*
# 백업 파일들
.backup/
*_original.*
*_backup.*
*_old.*

190
README.md
View File

@@ -1,15 +1,37 @@
# Imagen4 MCP Server with Preview Images # Imagen4 MCP Server with Preview Images & Unicode Support
Google Imagen 4를 사용한 AI 이미지 생성 MCP 서버입니다. 하나의 `main.py` 파일로 모든 기능이 통합되어 있니다. Google Imagen 4를 사용한 AI 이미지 생성 MCP 서버입니다. 하나의 `main.py` 파일로 모든 기능이 통합되어 있으며, **한글 프롬프트를 완벽 지원**합니다.
## 🚀 주요 기능 ## 🚀 주요 기능
- **고품질 이미지 생성**: 2048x2048 PNG 이미지 생성 - **고품질 이미지 생성**: 2048x2048 PNG 이미지 생성
- **미리보기 이미지**: 512x512 JPEG 미리보기를 base64로 제공 - **미리보기 이미지**: 512x512 JPEG 미리보기를 base64로 제공
- **파일 저장**: 원본 PNG + 메타데이터 JSON 저장 - **한글 프롬프트 지원**: 유니코드 로깅으로 한글 프롬프트 완벽 지원
- **파일 저장**: 원본 PNG + 메타데이터 JSON 저장 (UTF-8 인코딩)
- **재생성**: JSON 파일로부터 동일한 설정으로 재생성 - **재생성**: JSON 파일로부터 동일한 설정으로 재생성
- **랜덤 시드**: 재현 가능한 결과를 위한 시드 생성 - **랜덤 시드**: 재현 가능한 결과를 위한 시드 생성
## 🌐 유니코드 지원 개선사항
### 문제 해결
기존 버전에서 한글 프롬프트 로깅 시 발생했던 글자 깨짐 현상을 완전히 해결했습니다:
**이전 (깨진 로그):**
```
2025-08-21 11:34:52,783 - imagen4-mcp-server - INFO - Starting image generation: ' غ Ȱ ִ Ƹ ٿ ҳ , ǻ dz, Ȳ ݺ , ٴ ٶ 鸮 Ӹ ī , ڿ ', Seed: 2088268492
```
**현재 (올바른 로그):**
```
2025-08-21 11:34:52,783 - imagen4-mcp-server - INFO - Starting image generation: '아름다운 석양이 산 너머로 지는 모습, 따뜻한 오렌지색, 황금빛 구름', Seed: 2088268492
```
### 개선 내용
1. **UnicodeStreamHandler**: Windows 콘솔에서 UTF-8 출력 지원
2. **UnicodeFormatter**: 로그 메시지의 유니코드 문자 안전 처리
3. **ensure_unicode_string()**: 모든 문자열을 UTF-8로 안전하게 변환
4. **Windows 콘솔 설정**: `chcp 65001``PYTHONIOENCODING=utf-8` 자동 설정
## 📦 설치 ## 📦 설치
### 1. 의존성 설치 ### 1. 의존성 설치
@@ -38,13 +60,26 @@ OUTPUT_PATH=./generated_images
### 서버 실행 ### 서버 실행
#### Windows #### Windows (유니코드 지원)
```bash
run_unicode.bat
```
#### 기본 실행
```bash ```bash
run.bat run.bat
``` ```
#### 직접 실행 #### 직접 실행 (유니코드 환경 설정)
```bash ```bash
# Windows
chcp 65001
set PYTHONIOENCODING=utf-8
set PYTHONUTF8=1
python main.py
# Linux/Mac
export PYTHONIOENCODING=utf-8
python main.py python main.py
``` ```
@@ -58,7 +93,11 @@ python main.py
"imagen4": { "imagen4": {
"command": "python", "command": "python",
"args": ["main.py"], "args": ["main.py"],
"cwd": "D:\\Project\\little-fairy\\imagen4" "cwd": "D:\\Project\\imagen4",
"env": {
"PYTHONIOENCODING": "utf-8",
"PYTHONUTF8": "1"
}
} }
} }
} }
@@ -67,16 +106,21 @@ python main.py
## 🛠️ 사용 가능한 도구 ## 🛠️ 사용 가능한 도구
### 1. generate_image ### 1. generate_image
고품질 이미지를 생성하고 미리보기를 제공합니다. 고품질 이미지를 생성하고 미리보기를 제공합니다. **한글 프롬프트 완벽 지원!**
**파라미터:** **파라미터:**
- `prompt` (필수): 이미지 생성 프롬프트 - `prompt` (필수): 이미지 생성 프롬프트 (한글/영어 모두 지원)
- `seed` (필수): 재현 가능한 결과를 위한 시드 값 - `seed` (필수): 재현 가능한 결과를 위한 시드 값
- `negative_prompt` (선택): 제외할 요소 지정 - `negative_prompt` (선택): 제외할 요소 지정 (한글/영어 모두 지원)
- `number_of_images` (선택): 생성할 이미지 수 (1-2) - `number_of_images` (선택): 생성할 이미지 수 (1-2)
- `aspect_ratio` (선택): 종횡비 ("1:1", "9:16", "16:9", "3:4", "4:3") - `aspect_ratio` (선택): 종횡비 ("1:1", "9:16", "16:9", "3:4", "4:3")
- `save_to_file` (선택): 파일 저장 여부 - `save_to_file` (선택): 파일 저장 여부
**한글 프롬프트 예시:**
```
프롬프트: "아름다운 벚꽃이 만개한 봄날의 공원, 따뜻한 햇살이 나무들 사이로 스며드는 모습, 파스텔 톤의 분홍색과 초록색"
```
**응답 예시:** **응답 예시:**
``` ```
✅ Images have been successfully generated! ✅ Images have been successfully generated!
@@ -89,7 +133,7 @@ Preview 1 (base64 JPEG): /9j/4AAQSkZJRgABAQAAAQABAAD/2wBD...(67234 chars)
- ./generated_images/imagen4_20250821_143052_seed_1234567890.json - ./generated_images/imagen4_20250821_143052_seed_1234567890.json
⚙️ Generation Parameters: ⚙️ Generation Parameters:
- prompt: A beautiful sunset over mountains - prompt: 아름다운 벚꽃이 만개한 봄날의 공원, 따뜻한 햇살이 나무들 사이로...
- seed: 1234567890 - seed: 1234567890
- aspect_ratio: 1:1 - aspect_ratio: 1:1
- number_of_images: 1 - number_of_images: 1
@@ -99,7 +143,7 @@ Preview 1 (base64 JPEG): /9j/4AAQSkZJRgABAQAAAQABAAD/2wBD...(67234 chars)
이미지 생성용 랜덤 시드를 생성합니다. 이미지 생성용 랜덤 시드를 생성합니다.
### 3. regenerate_from_json ### 3. regenerate_from_json
저장된 JSON 파라미터 파일로부터 이미지를 재생성합니다. 저장된 JSON 파라미터 파일로부터 이미지를 재생성합니다. **한글 메타데이터 완벽 보존!**
## 🖼️ 미리보기 이미지 특징 ## 🖼️ 미리보기 이미지 특징
@@ -115,9 +159,40 @@ Preview 1 (base64 JPEG): /9j/4AAQSkZJRgABAQAAAQABAAD/2wBD...(67234 chars)
- **투명도 처리**: PNG 투명도를 흰색 배경으로 변환 - **투명도 처리**: PNG 투명도를 흰색 배경으로 변환
- **종횡비 유지**: 원본 비율을 유지하면서 크기 조정 - **종횡비 유지**: 원본 비율을 유지하면서 크기 조정
## 🌏 유니코드 로깅 기술적 세부사항
### 커스텀 로깅 핸들러
```python
class UnicodeStreamHandler(logging.StreamHandler):
"""Windows에서 UTF-8 출력을 보장하는 커스텀 핸들러"""
def __init__(self, stream=None):
super().__init__(stream)
# Windows 콘솔을 UTF-8로 재설정
if hasattr(self.stream, 'reconfigure'):
self.stream.reconfigure(encoding='utf-8', errors='replace')
```
### 문자열 안전 처리
```python
def ensure_unicode_string(value):
"""모든 문자열을 UTF-8 유니코드로 안전하게 변환"""
if isinstance(value, bytes):
return value.decode('utf-8', errors='replace')
elif isinstance(value, str):
return value
else:
return str(value)
```
### Windows 환경 자동 설정
- **코드페이지**: `chcp 65001` (UTF-8)
- **Python 환경변수**: `PYTHONIOENCODING=utf-8`, `PYTHONUTF8=1`
- **스트림 재설정**: stderr을 UTF-8 모드로 재구성
## 🧪 테스트 ## 🧪 테스트
기능을 테스트하려면: 한글 프롬프트 지원을 테스트하려면:
```bash ```bash
python test_main.py python test_main.py
@@ -127,24 +202,39 @@ python test_main.py
- 모든 클래스 및 함수 import - 모든 클래스 및 함수 import
- 이미지 처리 기능 - 이미지 처리 기능
- 미리보기 생성 기능 - 미리보기 생성 기능
- 유니코드 문자열 처리
### 한글 테스트 예시
```python
# 한글 프롬프트 테스트
korean_prompt = "아름다운 한국의 전통 한옥, 단풍이 물든 가을 정원"
result = await client.generate_image({
"prompt": korean_prompt,
"seed": 12345
})
```
## 📁 프로젝트 구조 ## 📁 프로젝트 구조
``` ```
imagen4/ imagen4/
├── main.py # 통합된 메인 서버 파일 ├── main.py # 통합된 메인 서버 파일 (유니코드 지원)
├── run.bat # Windows 실행 파일 ├── run.bat # 기본 Windows 실행 파일
├── run_unicode.bat # 유니코드 지원 Windows 실행 파일 (NEW!)
├── test_main.py # 테스트 스크립트 ├── test_main.py # 테스트 스크립트
├── claude_desktop_config.json # Claude Desktop 설정 ├── claude_desktop_config.json # Claude Desktop 설정
├── requirements.txt # 의존성 목록 ├── requirements.txt # 의존성 목록
├── .env # 환경 변수 (사용자가 생성) ├── .env # 환경 변수 (사용자가 생성)
├── generated_images/ # 생성된 이미지 저장소 ├── generated_images/ # 생성된 이미지 저장소
└── src/ └── src/
── connector/ # Google API 연결 모듈 ── connector/ # Google API 연결 모듈
├── __init__.py ├── __init__.py
├── config.py ├── config.py
├── imagen4_client.py ├── imagen4_client.py # 유니코드 지원 개선
└── utils.py └── utils.py
└── server/ # 서버 핸들러
├── enhanced_handlers.py # 유니코드 지원 개선
└── ...
``` ```
## 🔧 기술적 세부사항 ## 🔧 기술적 세부사항
@@ -156,49 +246,97 @@ imagen4/
- **중앙 정렬**: 목표 크기보다 작은 이미지는 중앙에 배치 - **중앙 정렬**: 목표 크기보다 작은 이미지는 중앙에 배치
### MCP 프로토콜 ### MCP 프로토콜
- **버전 3.0.0**: 미리보기 이미지 지원 - **버전 3.1.0**: 미리보기 이미지 + 유니코드 지원
- **비동기 처리**: asyncio 기반 안정적인 비동기 작업 - **비동기 처리**: asyncio 기반 안정적인 비동기 작업
- **오류 처리**: 상세한 로깅 및 사용자 친화적 오류 메시지 - **오류 처리**: 상세한 로깅 및 사용자 친화적 오류 메시지
- **타임아웃**: 6분 타임아웃으로 안전한 작업 보장 - **타임아웃**: 6분 타임아웃으로 안전한 작업 보장
- **유니코드 로깅**: 한글 프롬프트 완벽 표시
### 유니코드 처리
- **UTF-8 강제**: 모든 텍스트 입출력을 UTF-8로 처리
- **에러 복구**: 인코딩 오류 시 'replace' 모드로 복구
- **크로스 플랫폼**: Windows/Linux/Mac 모든 환경에서 동작
## 🐛 문제 해결 ## 🐛 문제 해결
### 일반적인 문제 ### 일반적인 문제
1. **Pillow 설치 오류** 1. **한글 로깅이 깨져 보이는 경우**
```bash
# Windows에서 run_unicode.bat 사용
run_unicode.bat
# 또는 수동으로 환경 설정
chcp 65001
set PYTHONIOENCODING=utf-8
python main.py
```
2. **Pillow 설치 오류**
```bash ```bash
pip install --upgrade pip pip install --upgrade pip
pip install Pillow pip install Pillow
``` ```
2. **Google Cloud 인증 오류** 3. **Google Cloud 인증 오류**
- 서비스 계정 키 파일 경로 확인 - 서비스 계정 키 파일 경로 확인
- PROJECT_ID가 올바른지 확인 - PROJECT_ID가 올바른지 확인
- Imagen API가 활성화되어 있는지 확인 - Imagen API가 활성화되어 있는지 확인
3. **메모리 부족** 4. **메모리 부족**
- 이미지 수를 1개로 제한 - 이미지 수를 1개로 제한
- 시스템 메모리 확인 (최소 8GB 권장) - 시스템 메모리 확인 (최소 8GB 권장)
### 로그 확인 ### 로그 확인
서버 실행 시 자세한 로그가 stderr로 출력됩니다: 서버 실행 시 자세한 로그가 stderr로 출력됩니다:
- 이미지 생성 진행 상황 - 이미지 생성 진행 상황 (한글 프롬프트 포함)
- 미리보기 생성 과정 - 미리보기 생성 과정
- 파일 저장 상태 - 파일 저장 상태
- 오류 및 경고 메시지 - 오류 및 경고 메시지
**올바른 한글 로그 예시:**
```
2025-08-21 11:34:52,783 - imagen4-mcp-server - INFO - Starting image generation: '아름다운 석양이 산 너머로 지는 모습...', Seed: 2088268492
2025-08-21 11:34:52,783 - src.connector.imagen4_client - INFO - Starting image generation - Prompt: '아름다운 석양이 산 너머로...', Seed: 2088268492
```
## 🌟 새로운 기능 (v3.1.0)
### ✨ 유니코드 완벽 지원
- **한글 프롬프트**: 로깅에서 완벽하게 표시
- **국제화 지원**: 일본어, 중국어, 아랍어 등 모든 유니코드 문자
- **Windows 호환성**: Windows 콘솔에서 완벽한 UTF-8 표시
### 🔧 개선된 로깅
- **UnicodeStreamHandler**: 커스텀 로깅 핸들러
- **안전한 문자열 처리**: 인코딩 오류 방지
- **크로스 플랫폼**: 모든 OS에서 일관된 동작
### 📦 배치 파일 업그레이드
- **run_unicode.bat**: UTF-8 환경 자동 설정
- **환경변수 자동 설정**: PYTHONIOENCODING, PYTHONUTF8
- **콘솔 설정**: chcp 65001 자동 실행
## 📄 라이센스 ## 📄 라이센스
MIT License - 자세한 내용은 LICENSE 파일을 참조하세요. MIT License - 자세한 내용은 LICENSE 파일을 참조하세요.
## 🎯 요약 ## 🎯 요약
통합된 `main.py`는 다음과 같은 이점을 제공합니다: 개선된 버전의 `main.py`는 다음과 같은 이점을 제공합니다:
- **완벽한 한글 지원**: 프롬프트와 로깅에서 한글 완벽 표시
- **단순성**: 하나의 파일로 모든 기능 제공 - **단순성**: 하나의 파일로 모든 기능 제공
- **효율성**: 512x512 JPEG 미리보기로 빠른 응답 - **효율성**: 512x512 JPEG 미리보기로 빠른 응답
- **호환성**: 기존 MCP 클라이언트와 완벽 호환 - **호환성**: 기존 MCP 클라이언트와 완벽 호환
- **국제화**: 모든 유니코드 문자 지원
- **확장성**: 필요에 따라 쉽게 기능 추가 가능 - **확장성**: 필요에 따라 쉽게 기능 추가 가능
Google Imagen 4의 강력한 이미지 생성 기능을 MCP 프로토콜을 통해 효율적으로 활용할 수 있습니다! **이제 한글 프롬프트로 아름다운 이미지 생성해보세요!**
```
프롬프트: "한국의 아름다운 설악산, 단풍이 물든 가을 풍경, 맑은 하늘과 구름"
```
Google Imagen 4의 강력한 이미지 생성 기능을 MCP 프로토콜을 통해 효율적으로 활용하되, 이제 **한글로도 자유롭게** 사용할 수 있습니다! 🎨🇰🇷

111
main.py
View File

@@ -57,12 +57,86 @@ except ImportError as e:
print("Please install Pillow: pip install Pillow", file=sys.stderr) print("Please install Pillow: pip install Pillow", file=sys.stderr)
sys.exit(1) sys.exit(1)
# Logging configuration # ==================== Unicode-Safe Logging Setup ====================
logging.basicConfig(
level=logging.DEBUG, class UnicodeStreamHandler(logging.StreamHandler):
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', """Custom stream handler that ensures proper Unicode handling"""
handlers=[logging.StreamHandler(sys.stderr)]
) def __init__(self, stream=None):
super().__init__(stream)
# Force UTF-8 encoding for Windows compatibility
if hasattr(self.stream, 'reconfigure'):
try:
self.stream.reconfigure(encoding='utf-8', errors='replace')
except:
pass
def emit(self, record):
try:
msg = self.format(record)
# Ensure the message is properly encoded as UTF-8
if isinstance(msg, str):
# For Windows, ensure proper UTF-8 handling
if sys.platform.startswith('win'):
msg = msg.encode('utf-8', errors='replace').decode('utf-8', errors='replace')
stream = self.stream
# Write with explicit UTF-8 encoding
if hasattr(stream, 'buffer'):
stream.buffer.write((msg + self.terminator).encode('utf-8', errors='replace'))
stream.buffer.flush()
else:
stream.write(msg + self.terminator)
if hasattr(stream, 'flush'):
stream.flush()
except Exception:
self.handleError(record)
# Custom formatter for proper Unicode handling
class UnicodeFormatter(logging.Formatter):
"""Custom formatter that ensures proper Unicode handling in log messages"""
def format(self, record):
# Ensure all arguments are properly handled for Unicode
if hasattr(record, 'args') and record.args:
safe_args = []
for arg in record.args:
if isinstance(arg, (dict, list)):
# Convert complex objects to string safely
safe_args.append(str(arg))
elif isinstance(arg, str):
# Ensure string is properly encoded
safe_args.append(arg)
else:
safe_args.append(str(arg))
record.args = tuple(safe_args)
return super().format(record)
# Set up UTF-8 encoding for stdout/stderr on Windows
if sys.platform.startswith('win'):
# Force UTF-8 encoding for Windows console
import locale
try:
# Try to set console to UTF-8
os.system('chcp 65001 >nul 2>&1')
# Set environment variables for Python UTF-8 mode
os.environ['PYTHONIOENCODING'] = 'utf-8'
except:
pass
# Logging configuration with Unicode support
unicode_handler = UnicodeStreamHandler(sys.stderr)
unicode_handler.setFormatter(UnicodeFormatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
))
# Configure root logger
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
root_logger.handlers.clear() # Remove default handlers
root_logger.addHandler(unicode_handler)
logger = logging.getLogger("imagen4-mcp-server") logger = logging.getLogger("imagen4-mcp-server")
@@ -257,7 +331,7 @@ def get_tools() -> List[Tool]:
# ==================== Utility Functions ==================== # ==================== Utility Functions ====================
def sanitize_args_for_logging(arguments: Dict[str, Any]) -> Dict[str, Any]: def sanitize_args_for_logging(arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Remove or truncate sensitive data from arguments for safe logging""" """Remove or truncate sensitive data from arguments for safe logging with Unicode support"""
safe_args = {} safe_args = {}
for key, value in arguments.items(): for key, value in arguments.items():
if isinstance(value, str): if isinstance(value, str):
@@ -267,9 +341,11 @@ def sanitize_args_for_logging(arguments: Dict[str, Any]) -> Dict[str, Any]:
# Truncate long image data # Truncate long image data
safe_args[key] = f"<image_data:{len(value)} chars>" safe_args[key] = f"<image_data:{len(value)} chars>"
elif len(value) > 1000: elif len(value) > 1000:
# Truncate any very long strings # Truncate any very long strings but preserve Unicode
safe_args[key] = f"{value[:100]}...<truncated:{len(value)} total chars>" truncated = value[:100]
safe_args[key] = f"{truncated}...<truncated:{len(value)} total chars>"
else: else:
# Keep the original string (including Korean characters)
safe_args[key] = value safe_args[key] = value
else: else:
safe_args[key] = value safe_args[key] = value
@@ -313,7 +389,7 @@ class Imagen4ToolHandlers:
text="Error: JSON file path is required." text="Error: JSON file path is required."
)] )]
# Load parameters from JSON file # Load parameters from JSON file with proper UTF-8 encoding
try: try:
with open(json_file_path, 'r', encoding='utf-8') as f: with open(json_file_path, 'r', encoding='utf-8') as f:
params = json.load(f) params = json.load(f)
@@ -415,9 +491,9 @@ class Imagen4ToolHandlers:
)] )]
async def handle_generate_image(self, arguments: Dict[str, Any]) -> List[TextContent]: async def handle_generate_image(self, arguments: Dict[str, Any]) -> List[TextContent]:
"""Image generation handler with preview image support""" """Image generation handler with preview image support and proper Unicode logging"""
try: try:
# Log arguments safely without exposing image data # Log arguments safely without exposing image data, but preserve Unicode
safe_args = sanitize_args_for_logging(arguments) safe_args = sanitize_args_for_logging(arguments)
logger.info(f"handle_generate_image called with arguments: {safe_args}") logger.info(f"handle_generate_image called with arguments: {safe_args}")
@@ -449,7 +525,9 @@ class Imagen4ToolHandlers:
save_to_file = arguments.get("save_to_file", True) save_to_file = arguments.get("save_to_file", True)
logger.info(f"Starting image generation: '{prompt[:50]}...', Seed: {seed}") # Log with proper Unicode handling for Korean text
prompt_preview = prompt[:50] + "..." if len(prompt) > 50 else prompt
logger.info(f"Starting image generation: '{prompt_preview}', Seed: {seed}")
# Generate image with timeout # Generate image with timeout
try: try:
@@ -631,7 +709,7 @@ async def main():
server = mcp_server.get_server() server = mcp_server.get_server()
logger.info("Imagen 4 MCP Server initialized successfully") logger.info("Imagen 4 MCP Server initialized successfully")
logger.info("Features: 512x512 JPEG preview images, base64 encoding, enhanced responses") logger.info("Features: 512x512 JPEG preview images, base64 encoding, enhanced responses, Unicode support")
# Run MCP server with better error handling # Run MCP server with better error handling
try: try:
@@ -642,12 +720,13 @@ async def main():
write_stream, write_stream,
InitializationOptions( InitializationOptions(
server_name="imagen4-mcp-server", server_name="imagen4-mcp-server",
server_version="3.0.0", server_version="3.1.0",
capabilities=server.get_capabilities( capabilities=server.get_capabilities(
notification_options=NotificationOptions(), notification_options=NotificationOptions(),
experimental_capabilities={ experimental_capabilities={
"preview_images": {}, "preview_images": {},
"base64_jpeg_previews": {} "base64_jpeg_previews": {},
"unicode_logging": {}
}, },
) )
) )

14
run.bat
View File

@@ -1,8 +1,13 @@
@echo off @echo off
echo Starting Imagen4 MCP Server with Preview Image Support... chcp 65001 > nul 2>&1
echo Features: 512x512 JPEG preview images, base64 encoding echo Starting Imagen4 MCP Server with Preview Image Support (Unicode Enabled)...
echo Features: 512x512 JPEG preview images, base64 encoding, Unicode logging support
echo. echo.
REM Set UTF-8 environment for Python
set PYTHONIOENCODING=utf-8
set PYTHONUTF8=1
REM Check if virtual environment exists REM Check if virtual environment exists
if not exist "venv\Scripts\activate.bat" ( if not exist "venv\Scripts\activate.bat" (
echo Creating virtual environment... echo Creating virtual environment...
@@ -38,8 +43,9 @@ if not exist ".env" (
exit /b 1 exit /b 1
) )
REM Run server REM Run server with UTF-8 support
echo Starting MCP server... echo Starting MCP server with Unicode support...
echo 한글 프롬프트 지원이 활성화되었습니다.
python main.py python main.py
REM Keep window open if there's an error REM Keep window open if there's an error

View File

@@ -1,9 +1,10 @@
""" """
Google Imagen 4 API Client Google Imagen 4 API Client with Unicode Logging Support
""" """
import asyncio import asyncio
import logging import logging
import sys
from typing import List, Optional from typing import List, Optional
from dataclasses import dataclass from dataclasses import dataclass
@@ -18,6 +19,16 @@ from .config import Config
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def ensure_unicode_string(value):
"""Ensure a value is a proper Unicode string"""
if isinstance(value, bytes):
return value.decode('utf-8', errors='replace')
elif isinstance(value, str):
return value
else:
return str(value)
@dataclass @dataclass
class ImageGenerationRequest: class ImageGenerationRequest:
"""Image generation request data class""" """Image generation request data class"""
@@ -28,6 +39,11 @@ class ImageGenerationRequest:
aspect_ratio: str = "1:1" aspect_ratio: str = "1:1"
model: str = "imagen-4.0-generate-001" # Model selection model: str = "imagen-4.0-generate-001" # Model selection
def __post_init__(self):
"""Ensure all string fields are properly Unicode encoded"""
self.prompt = ensure_unicode_string(self.prompt)
self.negative_prompt = ensure_unicode_string(self.negative_prompt)
def validate(self) -> None: def validate(self) -> None:
"""Validate request data""" """Validate request data"""
# Import here to avoid circular imports # Import here to avoid circular imports
@@ -71,7 +87,7 @@ class ImageGenerationResponse:
class Imagen4Client: class Imagen4Client:
"""Google Imagen 4 API client""" """Google Imagen 4 API client with Unicode logging support"""
def __init__(self, config: Config): def __init__(self, config: Config):
""" """
@@ -110,7 +126,7 @@ class Imagen4Client:
async def generate_image(self, request: ImageGenerationRequest) -> ImageGenerationResponse: async def generate_image(self, request: ImageGenerationRequest) -> ImageGenerationResponse:
""" """
Process image generation request with MCP-safe execution Process image generation request with MCP-safe execution and Unicode support
Args: Args:
request: Image generation request object request: Image generation request object
@@ -131,21 +147,37 @@ class Imagen4Client:
neg_stats = get_prompt_stats(request.negative_prompt) neg_stats = get_prompt_stats(request.negative_prompt)
logger.info(f"Negative prompt token analysis: {neg_stats['estimated_tokens']} tokens") logger.info(f"Negative prompt token analysis: {neg_stats['estimated_tokens']} tokens")
logger.info(f"Starting image generation - Prompt: '{request.prompt[:50]}...', Seed: {request.seed}, Model: {request.model}") # Log with proper Unicode support for Korean/international text
print(f"Aspect Ratio: {request.aspect_ratio}, Number of Images: {request.number_of_images}, Model: {request.model}") prompt_preview = request.prompt[:50] + "..." if len(request.prompt) > 50 else request.prompt
print(f"Prompt Tokens: {prompt_stats['estimated_tokens']}/{prompt_stats['max_tokens']}") logger.info(f"Starting image generation - Prompt: '{prompt_preview}', Seed: {request.seed}, Model: {request.model}")
# Use print statements for console output with explicit UTF-8 handling
try:
print(f"Aspect Ratio: {request.aspect_ratio}, Number of Images: {request.number_of_images}, Model: {request.model}")
print(f"Prompt Tokens: {prompt_stats['estimated_tokens']}/{prompt_stats['max_tokens']}")
# For Windows, ensure proper UTF-8 encoding
if sys.platform.startswith('win'):
# Try to encode/decode properly for Windows console
prompt_safe = request.prompt.encode('utf-8', errors='replace').decode('utf-8', errors='replace')
print(f"Prompt: {prompt_safe[:100]}{'...' if len(prompt_safe) > 100 else ''}")
else:
print(f"Prompt: {request.prompt[:100]}{'...' if len(request.prompt) > 100 else ''}")
except UnicodeEncodeError:
# Fallback for problematic characters
print(f"Prompt: <Unicode text, {len(request.prompt)} characters>")
# Create a new event loop if needed (for MCP compatibility) # Create a new event loop if needed (for MCP compatibility)
def _sync_generate_images(): def _sync_generate_images():
"""Synchronous wrapper for API call""" """Synchronous wrapper for API call"""
return self._client.models.generate_images( return self._client.models.generate_images(
model=request.model, model=request.model,
prompt=request.prompt, prompt=request.prompt, # This is now properly Unicode
config=GenerateImagesConfig( config=GenerateImagesConfig(
add_watermark=False, add_watermark=False,
aspect_ratio=request.aspect_ratio, aspect_ratio=request.aspect_ratio,
image_size="2K", # 2048x2048 image_size="2K", # 2048x2048
negative_prompt=request.negative_prompt, negative_prompt=request.negative_prompt, # This is now properly Unicode
number_of_images=request.number_of_images, number_of_images=request.number_of_images,
output_mime_type="image/png", output_mime_type="image/png",
person_generation="allow_all", person_generation="allow_all",

View File

@@ -1,5 +1,5 @@
""" """
Enhanced Tool Handlers for MCP Server with Preview Image Support Enhanced Tool Handlers for MCP Server with Preview Image Support and Unicode Logging
""" """
import asyncio import asyncio
@@ -7,6 +7,8 @@ import base64
import json import json
import random import random
import logging import logging
import sys
import os
from typing import List, Dict, Any from typing import List, Dict, Any
from mcp.types import TextContent, ImageContent from mcp.types import TextContent, ImageContent
@@ -17,23 +19,39 @@ from src.connector.utils import save_generated_images
from src.utils.image_utils import create_preview_image_b64, get_image_info from src.utils.image_utils import create_preview_image_b64, get_image_info
from src.server.enhanced_models import ImageGenerationResult, PreviewImageResponse from src.server.enhanced_models import ImageGenerationResult, PreviewImageResponse
# Configure Unicode logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Ensure proper Unicode handling for all string operations
def ensure_unicode_string(value):
"""Ensure a value is a proper Unicode string"""
if isinstance(value, bytes):
return value.decode('utf-8', errors='replace')
elif isinstance(value, str):
return value
else:
return str(value)
def sanitize_args_for_logging(arguments: Dict[str, Any]) -> Dict[str, Any]: def sanitize_args_for_logging(arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Remove or truncate sensitive data from arguments for safe logging""" """Remove or truncate sensitive data from arguments for safe logging with Unicode support"""
safe_args = {} safe_args = {}
for key, value in arguments.items(): for key, value in arguments.items():
if isinstance(value, str): if isinstance(value, str):
# Ensure proper Unicode handling
value = ensure_unicode_string(value)
# Check if it's likely base64 image data # Check if it's likely base64 image data
if (key in ['data', 'image_data', 'base64', 'preview_image_b64'] or if (key in ['data', 'image_data', 'base64', 'preview_image_b64'] or
(len(value) > 100 and value.startswith(('iVBORw0KGgo', '/9j/', 'R0lGOD')))): (len(value) > 100 and value.startswith(('iVBORw0KGgo', '/9j/', 'R0lGOD')))):
# Truncate long image data # Truncate long image data
safe_args[key] = f"<image_data:{len(value)} chars>" safe_args[key] = f"<image_data:{len(value)} chars>"
elif len(value) > 1000: elif len(value) > 1000:
# Truncate any very long strings # Truncate any very long strings but preserve Unicode characters
safe_args[key] = f"{value[:100]}...<truncated:{len(value)} total chars>" truncated = value[:100]
safe_args[key] = f"{truncated}...<truncated:{len(value)} total chars>"
else: else:
# Keep the original string (including Korean/Unicode characters)
safe_args[key] = value safe_args[key] = value
else: else:
safe_args[key] = value safe_args[key] = value
@@ -41,7 +59,7 @@ def sanitize_args_for_logging(arguments: Dict[str, Any]) -> Dict[str, Any]:
class EnhancedToolHandlers: class EnhancedToolHandlers:
"""Enhanced MCP tool handler class with preview image support""" """Enhanced MCP tool handler class with preview image support and Unicode logging"""
def __init__(self, config: Config): def __init__(self, config: Config):
"""Initialize handler""" """Initialize handler"""
@@ -75,7 +93,7 @@ class EnhancedToolHandlers:
text="Error: JSON file path is required." text="Error: JSON file path is required."
)] )]
# Load parameters from JSON file # Load parameters from JSON file with proper UTF-8 encoding
try: try:
with open(json_file_path, 'r', encoding='utf-8') as f: with open(json_file_path, 'r', encoding='utf-8') as f:
params = json.load(f) params = json.load(f)
@@ -180,9 +198,9 @@ class EnhancedToolHandlers:
)] )]
async def handle_generate_image(self, arguments: Dict[str, Any]) -> List[TextContent]: async def handle_generate_image(self, arguments: Dict[str, Any]) -> List[TextContent]:
"""Enhanced image generation handler with preview image support""" """Enhanced image generation handler with preview image support and proper Unicode logging"""
try: try:
# Log arguments safely without exposing image data # Log arguments safely without exposing image data but preserve Unicode
safe_args = sanitize_args_for_logging(arguments) safe_args = sanitize_args_for_logging(arguments)
logger.info(f"handle_generate_image called with arguments: {safe_args}") logger.info(f"handle_generate_image called with arguments: {safe_args}")
@@ -195,6 +213,9 @@ class EnhancedToolHandlers:
text="Error: Prompt is required." text="Error: Prompt is required."
)] )]
# Ensure prompt is properly handled as Unicode
prompt = ensure_unicode_string(prompt)
seed = arguments.get("seed") seed = arguments.get("seed")
if seed is None: if seed is None:
logger.error("No seed provided") logger.error("No seed provided")
@@ -206,7 +227,7 @@ class EnhancedToolHandlers:
# Create image generation request object # Create image generation request object
request = ImageGenerationRequest( request = ImageGenerationRequest(
prompt=prompt, prompt=prompt,
negative_prompt=arguments.get("negative_prompt", ""), negative_prompt=ensure_unicode_string(arguments.get("negative_prompt", "")),
number_of_images=arguments.get("number_of_images", 1), number_of_images=arguments.get("number_of_images", 1),
seed=seed, seed=seed,
aspect_ratio=arguments.get("aspect_ratio", "1:1"), aspect_ratio=arguments.get("aspect_ratio", "1:1"),
@@ -215,7 +236,9 @@ class EnhancedToolHandlers:
save_to_file = arguments.get("save_to_file", True) save_to_file = arguments.get("save_to_file", True)
logger.info(f"Starting image generation: '{prompt[:50]}...', Seed: {seed}") # Log with proper Unicode handling for Korean/international text
prompt_preview = prompt[:50] + "..." if len(prompt) > 50 else prompt
logger.info(f"Starting image generation: '{prompt_preview}', Seed: {seed}")
# Generate image with timeout # Generate image with timeout
try: try:
@@ -283,7 +306,6 @@ class EnhancedToolHandlers:
logger.info(f"Files saved: {saved_files}") logger.info(f"Files saved: {saved_files}")
# Verify files were created # Verify files were created
import os
for file_path in saved_files: for file_path in saved_files:
if os.path.exists(file_path): if os.path.exists(file_path):
size = os.path.getsize(file_path) size = os.path.getsize(file_path)