persona_create / modules /image_analyzer.py
haepada's picture
Update modules/image_analyzer.py
35931a6 verified
import os
import json
import random
from PIL import Image
# 물리적 특성 매핑 데이터 경로
SHAPE_TRAITS_PATH = "data/trait_mappings/shape_traits.json"
COLOR_TRAITS_PATH = "data/trait_mappings/color_traits.json"
MATERIAL_TRAITS_PATH = "data/trait_mappings/material_traits.json"
def load_trait_mappings():
"""물리적 특성-성격 매핑 데이터 로드"""
# 파일이 없으면 기본 매핑 생성
if not os.path.exists(SHAPE_TRAITS_PATH):
try:
os.makedirs(os.path.dirname(SHAPE_TRAITS_PATH), exist_ok=True)
default_shape_traits = {
"곡선형": {
"온기": (60, 80),
"친화성": (60, 80),
"창의성": (50, 70)
},
"직선형": {
"능력": (60, 80),
"신뢰성": (60, 80)
},
"대칭형": {
"신뢰성": (70, 90),
"능력": (60, 80)
},
"비대칭형": {
"창의성": (70, 90),
"유머감각": (60, 80)
},
"단순형": {
"능력": (60, 80),
"신뢰성": (50, 70)
},
"복잡형": {
"창의성": (70, 90),
"능력": (60, 80)
}
}
with open(SHAPE_TRAITS_PATH, 'w', encoding='utf-8') as f:
json.dump(default_shape_traits, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"형태-특성 매핑 파일 생성 오류: {str(e)}")
print("기본값을 사용합니다.")
default_shape_traits = {
"곡선형": {"온기": (60, 80), "친화성": (60, 80)},
"직선형": {"능력": (60, 80), "신뢰성": (60, 80)},
"대칭형": {"신뢰성": (70, 90)},
"비대칭형": {"창의성": (70, 90)},
"단순형": {"능력": (60, 80)},
"복잡형": {"창의성": (70, 90)}
}
# 색상 매핑
if not os.path.exists(COLOR_TRAITS_PATH):
try:
os.makedirs(os.path.dirname(COLOR_TRAITS_PATH), exist_ok=True)
default_color_traits = {
"밝은": {
"온기": (60, 80),
"친화성": (60, 80)
},
"어두운": {
"신뢰성": (60, 80),
"창의성": (60, 80)
},
"따뜻한": {
"온기": (70, 90),
"친화성": (60, 80)
},
"차가운": {
"신뢰성": (60, 80),
"능력": (60, 80)
},
"화려한": {
"창의성": (70, 90),
"유머감각": (60, 80)
},
"단색": {
"신뢰성": (60, 80),
"능력": (50, 70)
}
}
with open(COLOR_TRAITS_PATH, 'w', encoding='utf-8') as f:
json.dump(default_color_traits, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"색상-특성 매핑 파일 생성 오류: {str(e)}")
print("기본값을 사용합니다.")
default_color_traits = {
"밝은": {"온기": (60, 80)},
"어두운": {"신뢰성": (60, 80)},
"따뜻한": {"온기": (70, 90)},
"차가운": {"능력": (60, 80)},
"화려한": {"창의성": (70, 90)},
"단색": {"신뢰성": (60, 80)}
}
# 재질 매핑
if not os.path.exists(MATERIAL_TRAITS_PATH):
try:
os.makedirs(os.path.dirname(MATERIAL_TRAITS_PATH), exist_ok=True)
default_material_traits = {
"나무": {
"온기": (60, 80),
"신뢰성": (60, 80)
},
"금속": {
"능력": (70, 90),
"신뢰성": (60, 80)
},
"유리": {
"신뢰성": (60, 80),
"친화성": (40, 60)
},
"가죽": {
"온기": (60, 80),
"신뢰성": (70, 90)
},
"플라스틱": {
"능력": (50, 70),
"창의성": (50, 70)
},
"천": {
"온기": (70, 90),
"친화성": (60, 80)
},
"종이": {
"창의성": (60, 80),
"온기": (50, 70)
}
}
with open(MATERIAL_TRAITS_PATH, 'w', encoding='utf-8') as f:
json.dump(default_material_traits, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"재질-특성 매핑 파일 생성 오류: {str(e)}")
print("기본값을 사용합니다.")
default_material_traits = {
"나무": {"온기": (60, 80)},
"금속": {"능력": (70, 90)},
"유리": {"친화성": (40, 60)},
"가죽": {"신뢰성": (70, 90)},
"플라스틱": {"창의성": (50, 70)},
"천": {"친화성": (60, 80)},
"종이": {"창의성": (60, 80)}
}
# 매핑 데이터 로드
shape_traits = {}
color_traits = {}
material_traits = {}
try:
if os.path.exists(SHAPE_TRAITS_PATH):
with open(SHAPE_TRAITS_PATH, 'r', encoding='utf-8') as f:
shape_traits = json.load(f)
else:
shape_traits = default_shape_traits
if os.path.exists(COLOR_TRAITS_PATH):
with open(COLOR_TRAITS_PATH, 'r', encoding='utf-8') as f:
color_traits = json.load(f)
else:
color_traits = default_color_traits
if os.path.exists(MATERIAL_TRAITS_PATH):
with open(MATERIAL_TRAITS_PATH, 'r', encoding='utf-8') as f:
material_traits = json.load(f)
else:
material_traits = default_material_traits
return {
"shape": shape_traits,
"color": color_traits,
"material": material_traits
}
except Exception as e:
print(f"트레이트 매핑 로드 오류: {str(e)}")
# 기본 매핑 제공
default_mappings = {
"shape": default_shape_traits if 'default_shape_traits' in locals() else {
"곡선형": {"온기": (60, 80)},
"직선형": {"능력": (60, 80)},
},
"color": default_color_traits if 'default_color_traits' in locals() else {
"밝은": {"온기": (60, 80)},
"어두운": {"신뢰성": (60, 80)},
},
"material": default_material_traits if 'default_material_traits' in locals() else {
"나무": {"온기": (60, 80)},
"금속": {"능력": (70, 90)},
}
}
return default_mappings
def analyze_image(image_path):
"""
이미지를 분석하여 물리적 특성과 그에 따른 성격 특성을 반환합니다.
Args:
image_path: 파일 경로 문자열 또는 File 컴포넌트 출력 객체
Returns:
이미지 분석 결과와 추천 특성값
"""
if image_path is None:
print("이미지가 없습니다.")
return {}, 50, 50, 50, 50, 50, 50, "", ""
try:
print(f"이미지 분석 시작: {image_path}")
# 이미지 로드 시도
try:
# 파일 경로 처리 - 다양한 형식 지원
if isinstance(image_path, str):
# 문자열 경로
img = Image.open(image_path)
print(f"문자열 경로에서 이미지 로드 성공: {img.format}, {img.size}, {img.mode}")
elif isinstance(image_path, dict):
# File 컴포넌트에서 반환된 딕셔너리 처리
if 'path' in image_path:
# 일반적인 File 컴포넌트 출력 형식
img = Image.open(image_path['path'])
print(f"File 컴포넌트(path 키)에서 이미지 로드 성공: {img.format}, {img.size}, {img.mode}")
elif 'name' in image_path:
# 일부 환경에서는 name 키를 사용할 수 있음
img = Image.open(image_path['name'])
print(f"File 컴포넌트(name 키)에서 이미지 로드 성공: {img.format}, {img.size}, {img.mode}")
else:
# 알 수 없는 딕셔너리 형식
print(f"지원되지 않는 딕셔너리 형식: {image_path.keys()}")
raise ValueError(f"지원하지 않는 이미지 딕셔너리 형식: {list(image_path.keys())}")
elif hasattr(image_path, 'name'):
# 파일 객체 형식
img = Image.open(image_path.name)
print(f"파일 객체에서 이미지 로드 성공: {img.format}, {img.size}, {img.mode}")
else:
# PIL Image 객체인지 확인
if hasattr(image_path, 'format') and hasattr(image_path, 'mode'):
img = image_path
print(f"PIL Image 객체 직접 사용: {img.format}, {img.size}, {img.mode}")
else:
# 기타 타입 처리
print(f"지원되지 않는 이미지 데이터 타입: {type(image_path)}")
raise ValueError(f"지원하지 않는 이미지 형식: {type(image_path)}")
except Exception as img_error:
print(f"이미지 로드 실패: {str(img_error)}")
return {}, 50, 50, 50, 50, 50, 50, "", ""
# 분석 로직 (더미 데이터 생성)
physical_features = {
"shape": random.choice(["곡선형", "직선형", "대칭형", "비대칭형", "단순형", "복잡형"]),
"color": random.choice(["밝은", "어두운", "따뜻한", "차가운", "화려한", "단색"]),
"material": random.choice(["나무", "금속", "유리", "가죽", "플라스틱", "천", "종이"])
}
# 물체 유형 추정
object_types = ["전자기기", "가구", "주방용품", "의류/액세서리", "책/문구류", "음악 기구", "장난감", "기타"]
estimated_type = random.choice(object_types)
# 물체 설명 생성
shape_desc = physical_features["shape"]
color_desc = physical_features["color"]
material_desc = physical_features["material"]
object_description = f"{color_desc} 색조의 {shape_desc} {material_desc} 물체입니다."
# 성격 특성 매핑 로드
trait_mappings = load_trait_mappings()
if trait_mappings:
# 기본 특성 값
traits = {
"온기": 50,
"능력": 50,
"신뢰성": 50,
"친화성": 50,
"창의성": 50,
"유머감각": 50
}
# 형태 기반 성격 특성 적용
shape = physical_features["shape"]
if shape in trait_mappings["shape"]:
for trait, value_range in trait_mappings["shape"][shape].items():
traits[trait] = random.randint(value_range[0], value_range[1])
# 색상 기반 성격 특성 적용
color = physical_features["color"]
if color in trait_mappings["color"]:
for trait, value_range in trait_mappings["color"][color].items():
# 이미 형태에서 설정한 값과 평균
if trait in traits:
traits[trait] = (traits[trait] + random.randint(value_range[0], value_range[1])) // 2
# 재질 기반 성격 특성 적용
material = physical_features["material"]
if material in trait_mappings["material"]:
for trait, value_range in trait_mappings["material"][material].items():
# 이미 설정한 값과 평균
if trait in traits:
traits[trait] = (traits[trait] + random.randint(value_range[0], value_range[1])) // 2
# 분석 결과 반환
analysis_result = {
"physical_features": physical_features,
"estimated_type": estimated_type,
"description": object_description,
"suggested_traits": traits
}
print(f"이미지 분석 완료: {estimated_type}")
return (
analysis_result,
traits["온기"],
traits["능력"],
traits["신뢰성"],
traits["친화성"],
traits["창의성"],
traits["유머감각"],
estimated_type,
object_description
)
# 트레이트 매핑이 없는 경우 기본값 반환
return {
"physical_features": physical_features,
"estimated_type": estimated_type,
"description": object_description,
}, 50, 50, 50, 50, 50, 50, estimated_type, object_description
except Exception as e:
print(f"이미지 분석 중 오류 발생: {str(e)}")
return {}, 50, 50, 50, 50, 50, 50, "", ""