60갑자 일주자료의 표준 데이터로 완전 통합한 명리학 시스템 구축기

소개



시도하고자 했던 것

명리학(사주) 교육 및 상담 시스템인 "한바둑 명리학 시스템"을 개발하면서,

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_fields

python

# 필드 매핑 규칙 정의 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 development

python

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 health

python

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_fields

python

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 설계



1
2개의 답글

뉴스레터 무료 구독

👉 이 게시글도 읽어보세요