Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -2,7 +2,7 @@ import gradio as gr
|
|
2 |
import datetime
|
3 |
import re
|
4 |
|
5 |
-
class
|
6 |
def __init__(self):
|
7 |
# 천간 (하늘줄기)
|
8 |
self.heavenly_stems = ['갑', '을', '병', '정', '무', '기', '경', '신', '임', '계']
|
@@ -19,45 +19,93 @@ class SajuCalculator:
|
|
19 |
'술': '토', '해': '수'
|
20 |
}
|
21 |
|
22 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
self.ten_gods = {
|
24 |
-
'
|
25 |
-
'
|
26 |
-
'
|
27 |
-
'
|
28 |
-
'
|
|
|
29 |
}
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
# 지역별 시간 보정 (서울 기준 분 단위)
|
32 |
self.location_offsets = {
|
33 |
-
'서울': 0, '서울특별시': 0, '경기': 0, '경기도': 0, '인천': 0,
|
34 |
-
'강원': +12, '강원도': +12, '춘천': +12, '
|
35 |
'충북': -8, '충청북도': -8, '청주': -8, '충주': 0,
|
36 |
-
'충남': -16, '충청남도': -16, '대전': -12, '
|
37 |
'전북': -20, '전라북도': -20, '전주': -20, '군산': -24,
|
38 |
-
'전남': -24, '전라남도': -24, '광주': -20, '
|
39 |
-
'경북': +8, '경상북도': +8, '대구': +4, '
|
40 |
-
'경남': -4, '경상남도': -4, '부산': +12, '
|
41 |
'제주': -20, '제주도': -20, '제주시': -20, '서귀포': -20
|
42 |
}
|
43 |
|
44 |
def get_location_offset(self, location):
|
45 |
-
"""
|
46 |
if not location:
|
47 |
return 0
|
48 |
-
|
49 |
location = location.strip()
|
50 |
-
|
51 |
-
# 정확한 매칭 시도
|
52 |
-
if location in self.location_offsets:
|
53 |
-
return self.location_offsets[location]
|
54 |
-
|
55 |
-
# 부분 매칭 시도
|
56 |
for key, offset in self.location_offsets.items():
|
57 |
if key in location or location in key:
|
58 |
return offset
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
-
return
|
61 |
|
62 |
def parse_date(self, date_str):
|
63 |
"""날짜 파싱"""
|
@@ -120,23 +168,28 @@ class SajuCalculator:
|
|
120 |
return hour, minute
|
121 |
|
122 |
def get_ganzhi(self, year, month, day, hour):
|
123 |
-
"""간지 계산"""
|
124 |
-
|
125 |
-
|
126 |
|
|
|
|
|
|
|
127 |
days_diff = (target_date - base_date).days
|
128 |
|
129 |
-
# 연주 계산
|
130 |
-
|
131 |
-
|
|
|
132 |
|
133 |
-
# 월주 계산
|
134 |
-
month_stem_index = (year_stem_index * 2 +
|
135 |
-
month_branch_index = (
|
136 |
|
137 |
# 일주 계산
|
138 |
-
|
139 |
-
|
|
|
140 |
|
141 |
# 시주 계산
|
142 |
hour_branch_index = ((hour + 1) // 2) % 12
|
@@ -164,17 +217,27 @@ class SajuCalculator:
|
|
164 |
return element_count
|
165 |
|
166 |
def get_ten_gods_analysis(self, ganzhi):
|
167 |
-
"""십신 분석"""
|
168 |
day_stem = ganzhi['day'][0]
|
169 |
-
day_element = self.five_elements[day_stem]
|
170 |
|
171 |
analysis = {}
|
172 |
for pillar_name, pillar in ganzhi.items():
|
173 |
-
|
174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
|
176 |
-
|
177 |
-
|
|
|
|
|
178 |
|
179 |
analysis[pillar_name] = {
|
180 |
'stem_relation': stem_relation,
|
@@ -183,288 +246,197 @@ class SajuCalculator:
|
|
183 |
|
184 |
return analysis
|
185 |
|
186 |
-
def
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
def get_element_balance_advice(elements):
|
198 |
-
"""오행 균형에 따른 조언"""
|
199 |
-
max_element = max(elements, key=elements.get)
|
200 |
-
min_element = min(elements, key=elements.get)
|
201 |
-
|
202 |
-
advice = f"현재 {max_element}가 가장 강하고 {min_element}가 가장 약합니다. "
|
203 |
-
|
204 |
-
if elements[max_element] - elements[min_element] > 2:
|
205 |
-
advice += f"{min_element}를 보강하고 {max_element}의 기운을 조절하는 것이 좋겠습니다."
|
206 |
-
else:
|
207 |
-
advice += "전체적으로 균형이 잘 잡혀 있는 편입니다."
|
208 |
-
|
209 |
-
return advice
|
210 |
|
211 |
def format_saju_result(calculator, ganzhi, elements, ten_gods, birth_info):
|
212 |
-
"""사주 결과 포맷팅 - 표
|
213 |
|
214 |
-
# 오행별 색상
|
215 |
-
|
216 |
-
'목': '#28a745',
|
217 |
-
'화': '#dc3545',
|
218 |
-
'토': '#ffc107',
|
219 |
-
'금': '#6c757d',
|
220 |
-
'수': '#007bff'
|
221 |
}
|
222 |
|
223 |
-
def
|
224 |
-
|
225 |
-
return f'<span style="color: {color}; font-weight: bold;">{char}</span>'
|
226 |
|
227 |
-
def
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
|
|
233 |
|
234 |
# 시간 보정 정보
|
235 |
-
|
236 |
if birth_info['location_offset'] != 0:
|
237 |
sign = "+" if birth_info['location_offset'] > 0 else ""
|
238 |
-
|
239 |
### ⏰ 출생지 시간 보정
|
240 |
- **입력 시간**: {birth_info['original_time']}
|
241 |
-
- **보정 시간**: {birth_info['corrected_time']}
|
|
|
242 |
"""
|
243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
result = f"""
|
245 |
-
# 🔮 사주명리 만세력
|
246 |
|
247 |
-
## 📋
|
248 |
-
- **생년월일**: {birth_info['birth_datetime'].strftime('%Y년 %m월 %d일')}
|
249 |
-
- **출생시간**: {birth_info['corrected_time']}
|
250 |
- **성별**: {birth_info['gender']}
|
251 |
-
{
|
252 |
-
|
253 |
|
254 |
-
|
255 |
|
256 |
-
|
257 |
-
|
258 |
-
|
|
259 |
-
|
260 |
-
|
|
261 |
-
|
|
|
|
|
|
|
|
262 |
|
263 |
</div>
|
264 |
|
265 |
-
|
266 |
|
267 |
-
|
268 |
|
269 |
-
|
270 |
-
|:---:|:---:|:---:|:---:|
|
271 |
-
| {get_colored_element('목', '목')} | {elements['목']}개 | {(elements['목']/8*100):.1f}% | {'강함' if elements['목'] >= 3 else '보통' if elements['목'] >= 2 else '약함'} |
|
272 |
-
| {get_colored_element('화', '화')} | {elements['화']}개 | {(elements['화']/8*100):.1f}% | {'강함' if elements['화'] >= 3 else '보통' if elements['화'] >= 2 else '약함'} |
|
273 |
-
| {get_colored_element('토', '토')} | {elements['토']}개 | {(elements['토']/8*100):.1f}% | {'강함' if elements['토'] >= 3 else '보통' if elements['토'] >= 2 else '약함'} |
|
274 |
-
| {get_colored_element('금', '금')} | {elements['금']}개 | {(elements['금']/8*100):.1f}% | {'강함' if elements['금'] >= 3 else '보통' if elements['금'] >= 2 else '약함'} |
|
275 |
-
| {get_colored_element('수', '수')} | {elements['수']}개 | {(elements['수']/8*100):.1f}% | {'강함' if elements['수'] >= 3 else '보통' if elements['수'] >= 2 else '약함'} |
|
276 |
|
277 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
278 |
|
279 |
-
|
280 |
-
"""
|
281 |
-
|
282 |
-
max_element = max(elements, key=elements.get)
|
283 |
-
min_element = min(elements, key=elements.get)
|
284 |
-
|
285 |
-
result += f"- **가장 강한 오행**: {get_colored_element(max_element, max_element)} ({elements[max_element]}개)\n"
|
286 |
-
result += f"- **가장 약한 오행**: {get_colored_element(min_element, min_element)} ({elements[min_element]}개)\n"
|
287 |
|
288 |
-
|
289 |
-
## 🎭 십신(十神) 분석표
|
290 |
|
291 |
-
<div style="
|
292 |
|
293 |
-
|
|
294 |
-
|
295 |
-
|
|
296 |
-
|
|
|
|
|
|
297 |
|
298 |
</div>
|
299 |
|
300 |
-
## 💡
|
301 |
|
302 |
-
### 일간 분석
|
303 |
-
|
304 |
-
- **성격**: {get_element_personality(calculator.five_elements[ganzhi['day'][0]])}
|
305 |
|
306 |
-
|
307 |
-
|
|
|
|
|
|
|
|
|
|
|
308 |
|
309 |
---
|
310 |
|
311 |
-
### 📌
|
312 |
-
-
|
313 |
-
-
|
314 |
-
-
|
|
|
|
|
|
|
315 |
|
316 |
-
|
|
|
317 |
"""
|
318 |
|
319 |
return result
|
320 |
|
321 |
-
def
|
322 |
-
"""
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
# datetime 객체 생성 (보정된 시간 사용)
|
364 |
-
birth_datetime = datetime.datetime(year, month, day, corrected_hour, corrected_minute)
|
365 |
-
original_time = f"{hour:02d}:{minute:02d}"
|
366 |
-
corrected_time = f"{corrected_hour:02d}:{corrected_minute:02d}"
|
367 |
-
|
368 |
-
# 출생 정보 딕셔너리
|
369 |
-
birth_info = {
|
370 |
-
'birth_datetime': birth_datetime,
|
371 |
-
'gender': gender,
|
372 |
-
'birth_place': birth_place,
|
373 |
-
'original_time': original_time,
|
374 |
-
'corrected_time': corrected_time,
|
375 |
-
'location_offset': location_offset
|
376 |
-
}
|
377 |
-
|
378 |
-
# 간지 계산
|
379 |
-
ganzhi = calculator.get_ganzhi(year, month, day, corrected_hour)
|
380 |
-
|
381 |
-
# 오행 분석
|
382 |
-
elements = calculator.analyze_elements(ganzhi)
|
383 |
-
|
384 |
-
# 십신 분석
|
385 |
-
ten_gods = calculator.get_ten_gods_analysis(ganzhi)
|
386 |
-
|
387 |
-
# 결과 포맷팅
|
388 |
-
result = format_saju_result(calculator, ganzhi, elements, ten_gods, birth_info)
|
389 |
-
|
390 |
-
return result
|
391 |
-
|
392 |
-
except ValueError as ve:
|
393 |
-
return f"❌ 입력 오류: {str(ve)}\n\n💡 입력 예시:\n- 생년월일: 19851015, 1985-10-15\n- 시간: 1430, 14:30"
|
394 |
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
gr.HTML("""
|
402 |
-
<div style="text-align: center; padding: 20px;">
|
403 |
-
<h1>🔮 사주명리학 만세력 분석 시스템</h1>
|
404 |
-
<p>생년월일시와 출생지 정보를 입력하시면 상세한 만세력을 분석해드립니다.</p>
|
405 |
-
</div>
|
406 |
-
""")
|
407 |
-
|
408 |
-
with gr.Row():
|
409 |
-
with gr.Column(scale=1):
|
410 |
-
gr.HTML("<h3>📝 정보 입력</h3>")
|
411 |
-
|
412 |
-
birth_date = gr.Textbox(
|
413 |
-
label="생년월일",
|
414 |
-
placeholder="19851015 또는 1985-10-15",
|
415 |
-
info="8자리 숫자 또는 구분자 포함하여 입력"
|
416 |
-
)
|
417 |
-
|
418 |
-
birth_time = gr.Textbox(
|
419 |
-
label="태어난 시간 (선택사항)",
|
420 |
-
placeholder="1430 또는 14:30",
|
421 |
-
info="4자리 숫자 또는 구분자 포함하여 입력. 비우면 정오로 설정"
|
422 |
-
)
|
423 |
-
|
424 |
-
gender = gr.Radio(
|
425 |
-
choices=["남", "여"],
|
426 |
-
label="성별",
|
427 |
-
value="남"
|
428 |
-
)
|
429 |
-
|
430 |
-
birth_place = gr.Textbox(
|
431 |
-
label="출생지",
|
432 |
-
placeholder="서울특별시",
|
433 |
-
info="시/도 단위로 입력해주세요"
|
434 |
-
)
|
435 |
-
|
436 |
-
calculate_btn = gr.Button(
|
437 |
-
"🔮 만세력 분석하기",
|
438 |
-
variant="primary"
|
439 |
-
)
|
440 |
-
|
441 |
-
with gr.Row():
|
442 |
-
with gr.Column():
|
443 |
-
result_output = gr.Markdown(
|
444 |
-
label="분석 결과",
|
445 |
-
value="👆 위의 정보를 입력하고 '만세력 분석하기' 버튼을 클릭하세요."
|
446 |
-
)
|
447 |
-
|
448 |
-
# 이벤트 연결
|
449 |
-
calculate_btn.click(
|
450 |
-
fn=calculate_saju,
|
451 |
-
inputs=[birth_date, birth_time, gender, birth_place],
|
452 |
-
outputs=result_output
|
453 |
-
)
|
454 |
-
|
455 |
-
gr.HTML("""
|
456 |
-
<div style="text-align: center; padding: 20px; margin-top: 30px; border-top: 1px solid #eee;">
|
457 |
-
<p><small>※ 본 시스템은 전통 사주명리학을 기반으로 하며, 참고용으로만 활용해주시기 바랍니다.</small></p>
|
458 |
-
<p><small>※ 정확한 해석을 위해서는 전문가의 상담을 받으시기 바랍니다.</small></p>
|
459 |
-
</div>
|
460 |
-
""")
|
461 |
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
share=True
|
470 |
-
)
|
|
|
2 |
import datetime
|
3 |
import re
|
4 |
|
5 |
+
class AdvancedSajuCalculator:
|
6 |
def __init__(self):
|
7 |
# 천간 (하늘줄기)
|
8 |
self.heavenly_stems = ['갑', '을', '병', '정', '무', '기', '경', '신', '임', '계']
|
|
|
19 |
'술': '토', '해': '수'
|
20 |
}
|
21 |
|
22 |
+
# 오행별 음양
|
23 |
+
self.element_yin_yang = {
|
24 |
+
'갑': '양', '을': '음', '병': '양', '정': '음', '무': '양',
|
25 |
+
'기': '음', '경': '양', '신': '음', '임': '양', '계': '음',
|
26 |
+
'자': '양', '축': '음', '인': '양', '묘': '음', '진': '양',
|
27 |
+
'사': '음', '오': '양', '미': '음', '신': '양', '유': '음',
|
28 |
+
'술': '양', '해': '음'
|
29 |
+
}
|
30 |
+
|
31 |
+
# 십신 (더 정확한 계산)
|
32 |
self.ten_gods = {
|
33 |
+
('갑', '갑'): '비견', ('갑', '을'): '겁재', ('갑', '병'): '식신', ('갑', '정'): '상관',
|
34 |
+
('갑', '무'): '편재', ('갑', '기'): '정재', ('갑', '경'): '편관', ('갑', '신'): '정관',
|
35 |
+
('갑', '임'): '편인', ('갑', '계'): '정인',
|
36 |
+
('을', '갑'): '겁재', ('을', '을'): '비견', ('을', '병'): '상관', ('을', '정'): '식신',
|
37 |
+
('을', '무'): '정재', ('을', '기'): '편재', ('을', '경'): '정관', ('을', '신'): '편관',
|
38 |
+
('을', '임'): '정인', ('을', '계'): '편인'
|
39 |
}
|
40 |
|
41 |
+
# 24절기 (양력 기준 근사값)
|
42 |
+
self.solar_terms = [
|
43 |
+
(2, 4, '입춘'), (2, 19, '우수'), (3, 6, '경칩'), (3, 21, '춘분'),
|
44 |
+
(4, 5, '청명'), (4, 20, '곡우'), (5, 6, '입하'), (5, 21, '소만'),
|
45 |
+
(6, 6, '망종'), (6, 21, '하지'), (7, 7, '소서'), (7, 23, '대서'),
|
46 |
+
(8, 8, '입추'), (8, 23, '처서'), (9, 8, '백로'), (9, 23, '추분'),
|
47 |
+
(10, 8, '한로'), (10, 23, '상강'), (11, 7, '입동'), (11, 22, '소설'),
|
48 |
+
(12, 7, '대설'), (12, 22, '동지'), (1, 6, '소한'), (1, 20, '대한')
|
49 |
+
]
|
50 |
+
|
51 |
# 지역별 시간 보정 (서울 기준 분 단위)
|
52 |
self.location_offsets = {
|
53 |
+
'서울': 0, '서울특별시': 0, '경기': 0, '경기도': 0, '인천': 0,
|
54 |
+
'강원': +12, '강원도': +12, '춘천': +12, '강릉': +20, '원주': +8,
|
55 |
'충북': -8, '충청북도': -8, '청주': -8, '충주': 0,
|
56 |
+
'충남': -16, '충청남도': -16, '대전': -12, '천안': -12,
|
57 |
'전북': -20, '전라북도': -20, '전주': -20, '군산': -24,
|
58 |
+
'전남': -24, '전라남도': -24, '광주': -20, '목포': -32, '여수': -16,
|
59 |
+
'경북': +8, '경상북도': +8, '대구': +4, '포항': +20, '경주': +16,
|
60 |
+
'경남': -4, '경상남도': -4, '부산': +12, '울산': +16, '창원': +4, '진주': -8,
|
61 |
'제주': -20, '제주도': -20, '제주시': -20, '서귀포': -20
|
62 |
}
|
63 |
|
64 |
def get_location_offset(self, location):
|
65 |
+
"""출생지별 시간 보정"""
|
66 |
if not location:
|
67 |
return 0
|
|
|
68 |
location = location.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
for key, offset in self.location_offsets.items():
|
70 |
if key in location or location in key:
|
71 |
return offset
|
72 |
+
return 0
|
73 |
+
|
74 |
+
def get_solar_term_month(self, year, month, day):
|
75 |
+
"""절기를 고려한 정확한 월주 계산"""
|
76 |
+
# 입춘 기준으로 년도 결정
|
77 |
+
if month == 1 or month == 2:
|
78 |
+
# 입춘(2/4) 이전이면 전년도
|
79 |
+
lichun_date = datetime.date(year, 2, 4)
|
80 |
+
current_date = datetime.date(year, month, day)
|
81 |
+
if current_date < lichun_date:
|
82 |
+
year -= 1
|
83 |
+
|
84 |
+
# 절기 기준 월 계산
|
85 |
+
month_mapping = {
|
86 |
+
(2, 4): 1, # 입춘~경칩 = 정월
|
87 |
+
(3, 6): 2, # 경칩~청명 = 2월
|
88 |
+
(4, 5): 3, # 청명~입하 = 3월
|
89 |
+
(5, 6): 4, # 입하~망종 = 4월
|
90 |
+
(6, 6): 5, # 망종~소서 = 5월
|
91 |
+
(7, 7): 6, # 소서~입추 = 6월
|
92 |
+
(8, 8): 7, # 입추~백로 = 7월
|
93 |
+
(9, 8): 8, # 백로~한로 = 8월
|
94 |
+
(10, 8): 9, # 한로~입동 = 9월
|
95 |
+
(11, 7): 10, # 입동~대설 = 10월
|
96 |
+
(12, 7): 11, # 대설~소한 = 11월
|
97 |
+
(1, 6): 12 # 소한~입춘 = 12월
|
98 |
+
}
|
99 |
+
|
100 |
+
# 현재 날짜가 어느 절기 구간에 속하는지 확인
|
101 |
+
current_date = datetime.date(year if month >= 2 else year + 1, month, day)
|
102 |
+
|
103 |
+
for (term_month, term_day), lunar_month in month_mapping.items():
|
104 |
+
term_date = datetime.date(year if term_month >= 2 else year + 1, term_month, term_day)
|
105 |
+
if current_date >= term_date:
|
106 |
+
solar_month = lunar_month
|
107 |
|
108 |
+
return year, solar_month
|
109 |
|
110 |
def parse_date(self, date_str):
|
111 |
"""날짜 파싱"""
|
|
|
168 |
return hour, minute
|
169 |
|
170 |
def get_ganzhi(self, year, month, day, hour):
|
171 |
+
"""정확한 간지 계산 (절기 고려)"""
|
172 |
+
# 절기 기준 연도와 월 계산
|
173 |
+
adjusted_year, solar_month = self.get_solar_term_month(year, month, day)
|
174 |
|
175 |
+
# 기준일: 1900년 1월 1일 (경자년 정축월 갑인일)
|
176 |
+
base_date = datetime.date(1900, 1, 1)
|
177 |
+
target_date = datetime.date(year, month, day)
|
178 |
days_diff = (target_date - base_date).days
|
179 |
|
180 |
+
# 연주 계산 (절기 기준)
|
181 |
+
year_cycle = (adjusted_year - 1900) % 60
|
182 |
+
year_stem_index = year_cycle % 10
|
183 |
+
year_branch_index = year_cycle % 12
|
184 |
|
185 |
+
# 월주 계산 (절기 기준)
|
186 |
+
month_stem_index = (year_stem_index * 2 + solar_month - 1) % 10
|
187 |
+
month_branch_index = (solar_month + 1) % 12
|
188 |
|
189 |
# 일주 계산
|
190 |
+
day_cycle = (days_diff + 10) % 60 # 1900.1.1이 갑인일
|
191 |
+
day_stem_index = day_cycle % 10
|
192 |
+
day_branch_index = day_cycle % 12
|
193 |
|
194 |
# 시주 계산
|
195 |
hour_branch_index = ((hour + 1) // 2) % 12
|
|
|
217 |
return element_count
|
218 |
|
219 |
def get_ten_gods_analysis(self, ganzhi):
|
220 |
+
"""십신 분석 (정확한 계산)"""
|
221 |
day_stem = ganzhi['day'][0]
|
|
|
222 |
|
223 |
analysis = {}
|
224 |
for pillar_name, pillar in ganzhi.items():
|
225 |
+
stem = pillar[0]
|
226 |
+
branch = pillar[1]
|
227 |
+
|
228 |
+
# 천간 십신
|
229 |
+
if (day_stem, stem) in self.ten_gods:
|
230 |
+
stem_relation = self.ten_gods[(day_stem, stem)]
|
231 |
+
else:
|
232 |
+
# 기본 오행 관계로 계산
|
233 |
+
day_element = self.five_elements[day_stem]
|
234 |
+
stem_element = self.five_elements[stem]
|
235 |
+
stem_relation = self.get_basic_relation(day_element, stem_element)
|
236 |
|
237 |
+
# 지지 십신 (지지의 본기로 계산)
|
238 |
+
branch_element = self.five_elements[branch]
|
239 |
+
day_element = self.five_elements[day_stem]
|
240 |
+
branch_relation = self.get_basic_relation(day_element, branch_element)
|
241 |
|
242 |
analysis[pillar_name] = {
|
243 |
'stem_relation': stem_relation,
|
|
|
246 |
|
247 |
return analysis
|
248 |
|
249 |
+
def get_basic_relation(self, day_element, target_element):
|
250 |
+
"""기본 오행 관계 계산"""
|
251 |
+
relations = {
|
252 |
+
'목': {'목': '비견', '화': '식신', '토': '편재', '금': '편관', '수': '편인'},
|
253 |
+
'화': {'목': '편인', '화': '비견', '토': '식신', '금': '편재', '수': '편관'},
|
254 |
+
'토': {'목': '편관', '화': '편인', '토': '비견', '금': '식신', '수': '편재'},
|
255 |
+
'금': {'목': '편재', '화': '편관', '토': '편인', '금': '비견', '수': '식신'},
|
256 |
+
'수': {'목': '식신', '화': '편재', '토': '편관', '금': '편인', '수': '비견'}
|
257 |
+
}
|
258 |
+
return relations[day_element][target_element]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
|
260 |
def format_saju_result(calculator, ganzhi, elements, ten_gods, birth_info):
|
261 |
+
"""사주 결과 포맷팅 - 전문적인 표 형태"""
|
262 |
|
263 |
+
# 오행별 색상 및 이모지
|
264 |
+
element_info = {
|
265 |
+
'목': {'color': '#28a745', 'emoji': '🌳', 'name': '목(木)'},
|
266 |
+
'화': {'color': '#dc3545', 'emoji': '🔥', 'name': '화(火)'},
|
267 |
+
'토': {'color': '#ffc107', 'emoji': '🏔️', 'name': '토(土)'},
|
268 |
+
'금': {'color': '#6c757d', 'emoji': '⚔️', 'name': '금(金)'},
|
269 |
+
'수': {'color': '#007bff', 'emoji': '💧', 'name': '수(水)'}
|
270 |
}
|
271 |
|
272 |
+
def get_colored_char(char, element):
|
273 |
+
info = element_info[element]
|
274 |
+
return f'<span style="color: {info["color"]}; font-weight: bold; font-size: 18px;">{char}</span>'
|
275 |
|
276 |
+
def get_element_strength(count):
|
277 |
+
if count >= 3:
|
278 |
+
return '<span style="color: #dc3545;">**강함**</span>'
|
279 |
+
elif count == 2:
|
280 |
+
return '<span style="color: #ffc107;">**보통**</span>'
|
281 |
+
else:
|
282 |
+
return '<span style="color: #6c757d;">**약함**</span>'
|
283 |
|
284 |
# 시간 보정 정보
|
285 |
+
time_info = ""
|
286 |
if birth_info['location_offset'] != 0:
|
287 |
sign = "+" if birth_info['location_offset'] > 0 else ""
|
288 |
+
time_info = f"""
|
289 |
### ⏰ 출생지 시간 보정
|
290 |
- **입력 시간**: {birth_info['original_time']}
|
291 |
+
- **보정 시간**: {birth_info['corrected_time']}
|
292 |
+
- **보정값**: {birth_info['birth_place']} 기준 {sign}{birth_info['location_offset']}분
|
293 |
"""
|
294 |
|
295 |
+
# 사주 표 생성
|
296 |
+
year_stem = get_colored_char(ganzhi['year'][0], calculator.five_elements[ganzhi['year'][0]])
|
297 |
+
year_branch = get_colored_char(ganzhi['year'][1], calculator.five_elements[ganzhi['year'][1]])
|
298 |
+
month_stem = get_colored_char(ganzhi['month'][0], calculator.five_elements[ganzhi['month'][0]])
|
299 |
+
month_branch = get_colored_char(ganzhi['month'][1], calculator.five_elements[ganzhi['month'][1]])
|
300 |
+
day_stem = get_colored_char(ganzhi['day'][0], calculator.five_elements[ganzhi['day'][0]])
|
301 |
+
day_branch = get_colored_char(ganzhi['day'][1], calculator.five_elements[ganzhi['day'][1]])
|
302 |
+
hour_stem = get_colored_char(ganzhi['hour'][0], calculator.five_elements[ganzhi['hour'][0]])
|
303 |
+
hour_branch = get_colored_char(ganzhi['hour'][1], calculator.five_elements[ganzhi['hour'][1]])
|
304 |
+
|
305 |
result = f"""
|
306 |
+
# 🔮 사주명리 만세력 완전분석
|
307 |
|
308 |
+
## 📋 출생 정보
|
309 |
+
- **생년월일**: {birth_info['birth_datetime'].strftime('%Y년 %m월 %d일')} (양력)
|
310 |
+
- **출생시간**: {birth_info['corrected_time']}
|
311 |
- **성별**: {birth_info['gender']}
|
312 |
+
- **출생지**: {birth_info['birth_place']}
|
313 |
+
{time_info}
|
314 |
|
315 |
+
## 🏛️ 사주(四柱) 만세력 【절기 기준 정확 계산】
|
316 |
|
317 |
+
<div style="background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 20px; border-radius: 10px; margin: 20px 0;">
|
318 |
+
|
319 |
+
| **구분** | **시주(時柱)** | **일주(日柱)** | **월주(月柱)** | **연주(年柱)** |
|
320 |
+
|:--------:|:-------------:|:-------------:|:-------------:|:-------------:|
|
321 |
+
| **천간** | {hour_stem} | {day_stem} | {month_stem} | {year_stem} |
|
322 |
+
| **지지** | {hour_branch} | {day_branch} | {month_branch} | {year_branch} |
|
323 |
+
| **간지** | **{ganzhi['hour'][0]}{ganzhi['hour'][1]}** | **{ganzhi['day'][0]}{ganzhi['day'][1]}** | **{ganzhi['month'][0]}{ganzhi['month'][1]}** | **{ganzhi['year'][0]}{ganzhi['year'][1]}** |
|
324 |
+
| **의미** | 자식·말년 | 본인·배우자 | 부모·청년 | 조상·유년 |
|
325 |
+
| **오행** | {element_info[calculator.five_elements[ganzhi['hour'][0]]]['name']} / {element_info[calculator.five_elements[ganzhi['hour'][1]]]['name']} | {element_info[calculator.five_elements[ganzhi['day'][0]]]['name']} / {element_info[calculator.five_elements[ganzhi['day'][1]]]['name']} | {element_info[calculator.five_elements[ganzhi['month'][0]]]['name']} / {element_info[calculator.five_elements[ganzhi['month'][1]]]['name']} | {element_info[calculator.five_elements[ganzhi['year'][0]]]['name']} / {element_info[calculator.five_elements[ganzhi['year'][1]]]['name']} |
|
326 |
|
327 |
</div>
|
328 |
|
329 |
+
> **일간**: {get_colored_char(ganzhi['day'][0], calculator.five_elements[ganzhi['day'][0]])} - 당신의 본성을 나타내는 핵심 요소
|
330 |
|
331 |
+
## 🌟 오행(五行) 균형 분석
|
332 |
|
333 |
+
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin: 15px 0;">
|
|
|
|
|
|
|
|
|
|
|
|
|
334 |
|
335 |
+
| **오행** | **개수** | **비율** | **강약** | **특성** |
|
336 |
+
|:--------:|:--------:|:--------:|:--------:|:--------:|
|
337 |
+
| {element_info['목']['emoji']} **목(木)** | **{elements['목']}개** | {(elements['목']/8*100):.1f}% | {get_element_strength(elements['목'])} | 성장·창조·유연성 |
|
338 |
+
| {element_info['화']['emoji']} **화(火)** | **{elements['화']}개** | {(elements['화']/8*100):.1f}% | {get_element_strength(elements['화'])} | 열정·활동·표현력 |
|
339 |
+
| {element_info['토']['emoji']} **토(土)** | **{elements['토']}개** | {(elements['토']/8*100):.1f}% | {get_element_strength(elements['토'])} | 안정·신뢰·포용력 |
|
340 |
+
| {element_info['금']['emoji']} **금(金)** | **{elements['금']}개** | {(elements['금']/8*100):.1f}% | {get_element_strength(elements['금'])} | 정의·결단·리더십 |
|
341 |
+
| {element_info['수']['emoji']} **수(水)** | **{elements['수']}개** | {(elements['수']/8*100):.1f}% | {get_element_strength(elements['수'])} | 지혜·적응·사고력 |
|
342 |
|
343 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
|
345 |
+
## 🎭 십신(十神) 관계 분석
|
|
|
346 |
|
347 |
+
<div style="background: #fff3cd; padding: 15px; border-radius: 8px; margin: 15px 0;">
|
348 |
|
349 |
+
| **주(柱)** | **천간 십신** | **지지 십신** | **의미** |
|
350 |
+
|:----------:|:------------:|:------------:|:--------:|
|
351 |
+
| **시주** | {ten_gods['hour']['stem_relation']} | {ten_gods['hour']['branch_relation']} | 자식운·말년운 |
|
352 |
+
| **일주** | {ten_gods['day']['stem_relation']} | {ten_gods['day']['branch_relation']} | 본인·결혼운 |
|
353 |
+
| **월주** | {ten_gods['month']['stem_relation']} | {ten_gods['month']['branch_relation']} | 부모운·사회운 |
|
354 |
+
| **연주** | {ten_gods['year']['stem_relation']} | {ten_gods['year']['branch_relation']} | 조상운·초년운 |
|
355 |
|
356 |
</div>
|
357 |
|
358 |
+
## 💡 종합 운세 해석
|
359 |
|
360 |
+
### 🎯 일간 분석 (핵심 성격)
|
361 |
+
일간 **{get_colored_char(ganzhi['day'][0], calculator.five_elements[ganzhi['day'][0]])}**({element_info[calculator.five_elements[ganzhi['day'][0]]]['name']})의 특성:
|
|
|
362 |
|
363 |
+
{get_detailed_personality(calculator.five_elements[ganzhi['day'][0]])}
|
364 |
+
|
365 |
+
### ⚖️ 오행 균형 진단
|
366 |
+
{get_advanced_balance_advice(elements)}
|
367 |
+
|
368 |
+
### 🔮 운세 포인트
|
369 |
+
{get_fortune_points(ganzhi, elements, calculator)}
|
370 |
|
371 |
---
|
372 |
|
373 |
+
### 📌 분석 기준
|
374 |
+
- ✅ **절기 기준 계산**: 입춘을 기준으로 정확한 연주·월주 산정
|
375 |
+
- ✅ **출생지 시간 보정**: 지역별 경도차 반영
|
376 |
+
- ✅ **전통 명리학**: 정통 사주명리학 이론 적용
|
377 |
+
|
378 |
+
### ⚠️ 유의사항
|
379 |
+
본 분석은 전통 사주명리학을 기반으로 한 기본 해석입니다. 더 정확하고 개인화된 분석을 위해서는 전문가 상담을 권장드립니다.
|
380 |
|
381 |
+
---
|
382 |
+
*분석 완료: {datetime.datetime.now().strftime('%Y년 %m월 %d일 %H시 %M분')}*
|
383 |
"""
|
384 |
|
385 |
return result
|
386 |
|
387 |
+
def get_detailed_personality(element):
|
388 |
+
"""상세한 성격 분석"""
|
389 |
+
personalities = {
|
390 |
+
'목': """
|
391 |
+
- **성격**: 따뜻하고 인정 많으며, 성장과 발전을 추구하는 성향
|
392 |
+
- **장점**: 창의적, 유연한 사고, 협력적, 포용력이 강함
|
393 |
+
- **특징**: 새로운 것을 배우고 성장하려는 의욕이 강하며, 타인을 도우려는 마음이 큼
|
394 |
+
- **주의점**: 때로는 우유부단하거나 결정을 미루는 경향""",
|
395 |
+
|
396 |
+
'화': """
|
397 |
+
- **성격**: 밝고 활발하며, 열정적이고 사교적인 성향
|
398 |
+
- **장점**: 리더십, 표현력, 긍정적 에너지, 추진력이 강함
|
399 |
+
- **특징**: 사람들과 어울리기를 좋아하며, 새로운 도전을 즐김
|
400 |
+
- **주의점**: 때로는 성급하거나 감정적인 판단을 할 수 있음""",
|
401 |
+
|
402 |
+
'토': """
|
403 |
+
- **성격**: 차분하고 신중하며, 안정을 추구하는 성향
|
404 |
+
- **장점**: 책임감, 인내력, 신뢰성, 포용력이 뛰어남
|
405 |
+
- **특징**: 꾸준하고 성실하며, 다른 사람들의 중재자 역할을 잘함
|
406 |
+
- **주의점**: 때로는 변화에 적응이 늦거나 고집이 셀 수 있음""",
|
407 |
+
|
408 |
+
'금': """
|
409 |
+
- **성격**: 원칙적이고 정의로우며, 강한 의지력을 가진 성향
|
410 |
+
- **장점**: 결단력, 리더십, 정직함, 목표 지향적
|
411 |
+
- **특징**: 옳고 그름이 분명하며, 자신의 신념을 관철시키려 함
|
412 |
+
- **주의점**: 때로는 융통성이 부족하거나 타인에게 엄격할 수 있음""",
|
413 |
+
|
414 |
+
'수': """
|
415 |
+
- **성격**: 지혜롭고 사려 깊으며, 깊이 있는 사고를 하는 성향
|
416 |
+
- **장점**: 통찰력, 적응력, 학습능력, 직관력이 뛰어남
|
417 |
+
- **특징**: 상황을 정확히 파악하고 현명한 판단을 내리는 능력
|
418 |
+
- **주의점**: 때로는 지나치게 신중하거나 소극적일 수 있음"""
|
419 |
+
}
|
420 |
+
return personalities.get(element, "균형 잡힌 성격을 가지고 있습니다.")
|
421 |
+
|
422 |
+
def get_advanced_balance_advice(elements):
|
423 |
+
"""고급 오행 균형 조언"""
|
424 |
+
max_element = max(elements, key=elements.get)
|
425 |
+
min_element = min(elements, key=elements.get)
|
426 |
+
max_count = elements[max_element]
|
427 |
+
min_count = elements[min_element]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
|
429 |
+
advice = f"""
|
430 |
+
**🔸 강한 오행**: {max_element} ({max_count}개) - 이 기운이 강하게 나타남
|
431 |
+
**🔸 약한 오행**: {min_element} ({min_count}개) - 이 기운을 보강하면 좋음
|
432 |
+
|
433 |
+
**💫 균형 조절 방법**:
|
434 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
|
436 |
+
if max_count - min_count > 2:
|
437 |
+
advice += f"- {min_element}를 보강하는 색상, 방향, 직업을 선택\n"
|
438 |
+
advice += f"- {max_element}의 과도한 기운을 조절하는 것이 필요\n"
|
439 |
+
advice += "- 전체적인 조화를 위한 노력이 중요"
|
440 |
+
else:
|
441 |
+
advice += "- 현재 오행이 비교적 균형잡혀 있는 상태\n"
|
442 |
+
advice += "- 기존의 균형을 유지하면서 발전시키는 것이
|
|
|
|