소개
시도하고자 했던 것
명리학(사주) 교육 및 상담 시스템인 "한바둑 명리학 시스템"을 개발하면서,
60갑자 일주(日柱) 데이터를 체계적으로 정리하고자 했습니다.
하지만 문제가 있었습니다:
11개의 서로 다른 파일에 데이터가 흩어져 있음
8가지 다른 구조 (JSON 키명과 계층이 모두 다름)
중복, 누락, 비표준화로 인한 활용 불가능
향후 DB 마이그레이션과 AI 연동을 위해 표준화 필수
그 이유
60갑자는 명리학의 핵심 개념으로, 각 일주마다:
기본 특성 (오행, 음양)
성격과 심리
대인관계
직업과 재물운
건강과 생활
발전 방향
특징 요약
이 7가지 필드로 체계화하여,
사용자가 자신의 사주를 입력하면 AI가 자동으로 통변(해석)을 생성하는 시스템을 만들고자 했습니다.
하지만 수작업으로 60개 일주 × 7필드 = 420개 필드를 정리하는 것은 현실적으로 불가능했고,
Claude의 도움을 받기로 했습니다.
진행 방법
사용 도구
Claude Sonnet 4.5 (Computer Use)
Python 3 (데이터 분석 및 변환)
JSON (데이터 포맷)
Bash (파일 관리)
전체 프로세스 (3단계)
Phase 1: 파일 분석 및 자동 매핑
먼저 11개 파일의 구조를 분석했습니다.
프롬프트 예시:
11개 파일을 분석하고, 각 파일의 구조와 일주 개수를 파악해줘. 특히 필드 이름이 어떻게 되어 있는지 확인해줘.
실행 코드:
import json
import os
files = [
'5개_일주_7필드_통합_2.json',
'5개_일주_7필드_통합_3.json',
# ... 총 11개 파일
]
for filename in files:
with open(filename, 'r', encoding='utf-8') as f:
data = json.load(f)
# 구조 파악
if isinstance(data, dict):
if 'iljus' in data:
iljus = data['iljus']
elif 'data' in data:
iljus = data['data']
elif isinstance(data, list):
iljus = data
# 일주명 추출
for ilju in iljus:
name = ilju.get('pillar_name') or ilju.get('일주명') or ilju.get('ilju_name')
print(f"발견: {name}")python
import json import os files = [ '5개_일주_7필드_통합_2.json', '5개_일주_7필드_통합_3.json', # ... 총 11개 파일 ] for filename in files: with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) # 구조 파악 if isinstance(data, dict): if 'iljus' in data: iljus = data['iljus'] elif 'data' in data: iljus = data['data'] elif isinstance(data, list): iljus = data # 일주명 추출 for ilju in iljus: name = ilju.get('pillar_name') or ilju.get('일주명') or ilju.get('ilju_name') print(f"발견: {name}")
발견된 8가지 구조:
standard (29개): 필드1_기본_특성, 필드2_성격_심리 ...
english (5개): field1_intro, field2_personality ...
korean (5개): 서론, 기본성향, 특징 ...
alternative (6개): 개요, 성격과_기질 ...
daymaster (5개): basic_understanding, yin_yang_elements ...
summary_style1 (2개): element_structure, personality_core ...
summary_style2 (2개): field1_personality, field2_career ...
markdown (6개): content (긴 마크다운 텍스트)
자동 매핑 코드:
# 필드 매핑 규칙 정의
FIELD_MAPPINGS = {
'english': {
'field1_intro': '필드1_기본_특성',
'field2_personality': '필드2_성격_심리',
'field3_career_wealth': '필드4_직업_재물',
'field4_love_marriage': '필드3_대인관계_사회성',
'field5_health': '필드5_건강_생활',
'field6_fortune_cycles': '필드6_발전방향',
'field7_life_advice': '필드7_특징_요약'
},
# ... 총 8가지 매핑 규칙
}
def map_to_standard_fields(original_data, structure_type):
mapping = FIELD_MAPPINGS[structure_type]
standard_fields = {}
for original_key, standard_key in mapping.items():
if original_key in original_data:
standard_fields[standard_key] = original_data[original_key]
return standard_fieldspython
# 필드 매핑 규칙 정의 FIELD_MAPPINGS = { 'english': { 'field1_intro': '필드1_기본_특성', 'field2_personality': '필드2_성격_심리', 'field3_career_wealth': '필드4_직업_재물', 'field4_love_marriage': '필드3_대인관계_사회성', 'field5_health': '필드5_건강_생활', 'field6_fortune_cycles': '필드6_발전방향', 'field7_life_advice': '필드7_특징_요약' }, # ... 총 8가지 매핑 규칙 } def map_to_standard_fields(original_data, structure_type): mapping = FIELD_MAPPINGS[structure_type] standard_fields = {} for original_key, standard_key in mapping.items(): if original_key in original_data: standard_fields[standard_key] = original_data[original_key] return standard_fields
결과: 54개 일주 자동 변환 완료
Phase 2: 빈 필드 자동 생성
Phase 1 후 26개 일주에 빈 필드가 발견되었습니다.
프롬프트 예시:
빈 필드를 자동으로 채워줘. - 필드6 (발전방향): 일반론 템플릿 활용 - 필드7 (특징_요약): 다른 필드에서 핵심 문장 추출 - 필드5 (건강_생활): 오행론 기반 생성 - 필드1 (기본_특성): 필드2, 4에서 요약
발전방향 생성 코드:
def generate_field6_development(ilju):
name = ilju['간지']
development = f"**{name}일주의 발전 방향**\n\n"
development += f"""
**단기 목표 (1-3년)**
- 현재 분야에서의 전문성 강화
- 인적 네트워크 구축 및 확장
- 재정 기반 안정화
**중기 목표 (3-10년)**
- 자신만의 독특한 강점 개발
- 리더십 역량 키우기
- 안정적 수입원 다각화
**장기 발전**
- 지속 가능한 성장 패턴 확립
- 사회적 영향력 확대
- 후학 양성 및 지식 전수
"""
return developmentpython
def generate_field6_development(ilju): name = ilju['간지'] development = f"**{name}일주의 발전 방향**\n\n" development += f""" 단기 목표 (1-3년) - 현재 분야에서의 전문성 강화 - 인적 네트워크 구축 및 확장 - 재정 기반 안정화 중기 목표 (3-10년) - 자신만의 독특한 강점 개발 - 리더십 역량 키우기 - 안정적 수입원 다각화 장기 발전 - 지속 가능한 성장 패턴 확립 - 사회적 영향력 확대 - 후학 양성 및 지식 전수 """ return development
건강 관리 생성 코드:
def generate_field5_health(ilju):
ilgan = ilju['간지'][0] # 천간
# 오행별 주의 부위
health_by_element = {
'갑': ('목', '간담', '눈', '근육'),
'을': ('목', '간담', '신경계', '목덜미'),
'병': ('화', '심장', '소장', '혈액순환'),
'정': ('화', '심장', '눈', '정신'),
'무': ('토', '비위', '소화기', '피부'),
# ...
}
element, organs = health_by_element.get(ilgan, ('오행', '장부'))[:2]
health = f"""
**주의할 부위**
{ilgan}({element}) 일간으로 {organs}에 주의가 필요합니다.
**건강 관리 포인트**
1. 규칙적인 생활
2. 스트레스 관리
3. 균형 잡힌 식습관
4. 정기 검진
"""
return healthpython
def generate_field5_health(ilju): ilgan = ilju['간지'][0] # 천간 # 오행별 주의 부위 health_by_element = { '갑': ('목', '간담', '눈', '근육'), '을': ('목', '간담', '신경계', '목덜미'), '병': ('화', '심장', '소장', '혈액순환'), '정': ('화', '심장', '눈', '정신'), '무': ('토', '비위', '소화기', '피부'), # ... } element, organs = health_by_element.get(ilgan, ('오행', '장부'))[:2] health = f""" 주의할 부위 {ilgan}({element}) 일간으로 {organs}에 주의가 필요합니다. 건강 관리 포인트 1. 규칙적인 생활 2. 스트레스 관리 3. 균형 잡힌 식습관 4. 정기 검진 """ return health
결과: 41개 빈 필드 생성 완료
Phase 3: Markdown 텍스트 파싱
6개 일주는 긴 Markdown 형식 텍스트였습니다.
프롬프트 예시:
이 Markdown 텍스트를 7개 섹션으로 나눠줘. - ## 서론 → 필드1 - ## 성격, 성향 → 필드2 - ## 결혼, 가족 → 필드3 - ## 직업, 재물 → 필드4 - ## 건강 → 필드5 - ## 기타 → 필드6
파싱 코드:
import re
def parse_markdown_to_7fields(content):
sections = {}
current_section = None
current_content = []
# ## 헤더 기준으로 분리
for line in content.split('\n'):
if line.startswith('## '):
if current_section:
sections[current_section] = '\n'.join(current_content).strip()
current_section = re.sub(r'[^\w\s가-힣]', '', line.replace('##', '')).strip()
current_content = []
else:
if current_section:
current_content.append(line)
# 섹션을 필드로 매핑
standard_fields = {}
for section_name, content in sections.items():
if '서론' in section_name:
standard_fields['필드1_기본_특성'] = content
elif '성격' in section_name or '성향' in section_name:
standard_fields['필드2_성격_심리'] = content
# ...
return standard_fieldspython
import re def parse_markdown_to_7fields(content): sections = {} current_section = None current_content = [] # ## 헤더 기준으로 분리 for line in content.split('\n'): if line.startswith('## '): if current_section: sections[current_section] = '\n'.join(current_content).strip() current_section = re.sub(r'[^\w\s가-힣]', '', line.replace('##', '')).strip() current_content = [] else: if current_section: current_content.append(line) # 섹션을 필드로 매핑 standard_fields = {} for section_name, content in sections.items(): if '서론' in section_name: standard_fields['필드1_기본_특성'] = content elif '성격' in section_name or '성향' in section_name: standard_fields['필드2_성격_심리'] = content # ... return standard_fields
결과: 6개 일주 완전 파싱 (평균 13,000자 → 7필드 분배)
최종 통합
통합 코드:
# 60갑자 순서로 정렬
gapja_order = [
'갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유',
# ... 60개
]
sorted_iljus = []
for gapja in gapja_order:
if gapja in all_iljus_data:
sorted_iljus.append(all_iljus_data[gapja])
# 최종 JSON 생성
integrated_data = {
'metadata': {
'title': '60갑자 일주 완전 통합 데이터',
'version': '3.0',
'created_at': datetime.now().isoformat(),
'total_iljus': 60
},
'iljus': sorted_iljus
}
with open('60개_일주_표준화_완전판_v3_0_FINAL.json', 'w', encoding='utf-8') as f:
json.dump(integrated_data, f, ensure_ascii=False, indent=2)python
# 60갑자 순서로 정렬 gapja_order = [ '갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', # ... 60개 ] sorted_iljus = [] for gapja in gapja_order: if gapja in all_iljus_data: sorted_iljus.append(all_iljus_data[gapja]) # 최종 JSON 생성 integrated_data = { 'metadata': { 'title': '60갑자 일주 완전 통합 데이터', 'version': '3.0', 'created_at': datetime.now().isoformat(), 'total_iljus': 60 }, 'iljus': sorted_iljus } with open('60개_일주_표준화_완전판_v3_0_FINAL.json', 'w', encoding='utf-8') as f: json.dump(integrated_data, f, ensure_ascii=False, indent=2)
결과와 배운 점
최종 결과
✅ 60개 전체 일주 완성 (100%)
✅ 420개 필드 (60개 × 7필드) 모두 채움
✅ 588,104자의 구조화된 콘텐츠
✅ 1.25MB 통합 JSON 파일
필드별 평균 글자 수:
필드1 (기본_특성): 1,789자
필드2 (성격_심리): 1,853자
필드3 (대인관계_사회성): 1,329자
필드4 (직업_재물): 1,618자
필드5 (건강_생활): 1,109자
필드6 (발전방향): 925자
필드7 (특징_요약): 1,177자
배운 점
1. 작은 단위로 나누기
처음엔 "60개 파일을 한 번에 통합해줘"라고 했다가 실패했습 니다. 대신:
파일 구조 분석
비슷한 구조끼리 그룹화
Phase별 처리
최종 통합
이렇게 단계를 나누니 성공했습니다.
2. 원본 데이터 보존의 중요성
통합 JSON에 원본 데이터를 모두 보존했습니다:
{
"일주명": "갑자일주",
"표준_7필드": { ... },
"원본_데이터": { ... }, // 원본 보존!
"원본_파일": "10개_일주_통합_최종.json",
"변환_방법": "markdown_parsing"
}json
{ "일주명": "갑자일주", "표준_7필드": { ... }, "원본_데이터": { ... }, // 원본 보존! "원본_파일": "10개_일주_통합_최종.json", "변환_방법": "markdown_parsing" }
나중에 "이 변환이 맞나?"를 확인할 수 있어 안심이 되었습니다.
3. 검증 코드 작성
각 단계마다 검증 코드를 작성했습니다:
# 빈 필드 확인
empty_count = sum(1 for v in ilju['표준_7필드'].values() if not v.strip())
# 60갑자 순서 확인
missing = [i for i in range(1, 61) if i not in gapja_nums]
# 중복 확인
duplicates = {name: count for name, count in Counter(names).items() if count > 1}python
# 빈 필드 확인 empty_count = sum(1 for v in ilju['표준_7필드'].values() if not v.strip()) # 60갑자 순서 확인 missing = [i for i in range(1, 61) if i not in gapja_nums] # 중복 확인 duplicates = {name: count for name, count in Counter(names).items() if count > 1}
도움 받은 글 (옵션)
참고한 자료
Claude 공식 문서
Computer Use 가이드
파일 처리 베스트 프랙티스
명리학 참고 서적
『연해자평(淵海子平)』
『명리정종(命理正宗)』
『적천수(滴天髓)』
『자평진전(子平眞詮)』
데이터 표준화 사례
PostgreSQL JSON 처리
대용량 텍스트 구조화
벡터 DB 설계