fix korean prompt logging at mcp-server-imagen4.log
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -116,4 +116,10 @@ generated_images/
|
|||||||
|
|
||||||
# 임시 파일들
|
# 임시 파일들
|
||||||
temp_*
|
temp_*
|
||||||
cleanup*
|
cleanup*
|
||||||
|
|
||||||
|
# 백업 파일들
|
||||||
|
.backup/
|
||||||
|
*_original.*
|
||||||
|
*_backup.*
|
||||||
|
*_old.*
|
||||||
|
|||||||
190
README.md
190
README.md
@@ -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
111
main.py
@@ -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
14
run.bat
@@ -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
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user