File size: 27,103 Bytes
0758717
 
 
 
 
 
 
b4251f4
 
 
 
4fc7350
80f4b08
 
 
4fc7350
1ced91c
 
c4d4857
 
 
 
 
 
 
 
4fc7350
c4d4857
 
 
 
 
 
4fc7350
c4d4857
 
 
4fc7350
c4d4857
4fc7350
c4d4857
4fc7350
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
 
 
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
 
 
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c4d4857
 
 
1ced91c
 
 
 
 
 
 
 
 
 
 
0121f83
80f4b08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b4251f4
 
b49206c
0121f83
 
 
 
f4fafda
b4251f4
4fc7350
b49206c
 
 
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f4fafda
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0121f83
4fc7350
 
 
 
 
 
0758717
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
b4251f4
 
4fc7350
b4251f4
4fc7350
b4251f4
f4fafda
4fc7350
 
2498233
4fc7350
 
b4251f4
1ced91c
80f4b08
 
 
2c0b4ad
 
 
 
 
 
 
80f4b08
 
b4251f4
1ced91c
80f4b08
1ced91c
c4d4857
 
 
 
2c0b4ad
c4d4857
 
 
 
839f058
 
 
 
 
 
 
c4d4857
4fc7350
 
 
 
 
 
 
1ced91c
b4251f4
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2498233
4fc7350
 
 
 
 
 
 
 
 
2498233
4fc7350
 
 
 
 
b49206c
 
4fc7350
 
2498233
4fc7350
b4251f4
 
 
8697be1
 
 
77eed2b
b4251f4
8697be1
 
 
77eed2b
8697be1
 
 
 
77eed2b
 
80f4b08
77eed2b
80f4b08
77eed2b
 
 
 
 
 
b4251f4
0121f83
b4251f4
6887924
 
 
b4251f4
1ced91c
 
 
 
 
 
b4251f4
4fc7350
 
b4251f4
 
 
 
6887924
b4251f4
 
 
0121f83
b4251f4
 
4fc7350
 
b4251f4
 
 
0121f83
b4251f4
 
 
 
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b49206c
 
b4251f4
 
 
80f4b08
00cbac1
 
b4251f4
 
 
8697be1
 
 
80f4b08
77eed2b
b4251f4
 
0121f83
1ced91c
b4251f4
0121f83
 
1ced91c
 
b4251f4
 
 
 
 
4fc7350
 
 
b4251f4
4fc7350
 
 
2498233
b4251f4
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
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
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
## 這是 TAIA x H.I.T LLM線上共學社群的專題實作
##
## AI 紫微
##
## 開發者:葉浩銘 Bob、蔡靜穎 Jinny 2024-03
##
## model="gpt-3.5-turbo-16k"
## 在你的資料夾新增 .env 檔案,並在裡面寫入 API_KEY=你的API金鑰
import os
import openai
import gradio as gr
import json
from zhdate import ZhDate
from datetime import datetime

localrun = False # 上傳到 Hugging Space 時要設定成 False
DESKTOP_KEY = False

# 排紫微盤的參考變數
solar_year = 1998
solar_month = 5
solar_day = 18
time_hour = 3
time_min = 14
gender = 0

#命宮主星是 ming_table[self_palace_epos]

zi_adjust = 2

'''
排盤有以下幾個步驟

1. 定命宮等十二宮

2. 起寅首、定納音五行局

3. 定紫微星、天府星

4. 安十四主星

5. 最好也能(安生年四化星)

'''

def gen_chart(solar_year, solar_month, solar_day, time_hour, time_min, gender):
    from datetime import timedelta, datetime

    # 六十甲子納音歌
    fiveoldsong = [ 4, 2, 6, 4, 2, 6, 2, 6, 5, 2, 6, 5, 6, 5, 3, 6, 5, 3, 5, 3, 4, 5, 3, 4, 3, 4, 2, 3, 4, 2 ];

    # 五行局
    fiveway = ['水二局','木三局','金四局','土五局','火六局']

    # 紫微星查表
    ziwei_table = [2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,1,1,2,2,3,3,4,4,5,5,2,3,6,3,4,7,4,5,8,5,6,9,6,7,10,7,8,11,8,9,12,9,10,1,10,11,2,11,12,12,5,2,3,1,6,3,4,2,7,4,5,3,8,5,6,4,9,6,7,5,10,7,8,6,11,8,9,7,12,7,12,5,2,3,8,1,6,3,4,9,2,7,4,5,10,3,8,5,6,11,5,9,6,7,12,5,10,7,8,10,7,12,5,2,3,11,8,1,6,3,4,12,9,2,7,4,5,1,10,3,8,5,6,2,11,4,9,6,7];

    # 天府星查表
    tianfu_table = [5,4,3,2,1,12,11,10,9,8,7,6]
    
    # 地支表格
    earth_table = ['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥']
    
    # 命盤
    ming_table = ['E','','','','','','','','','','','','']
    

    def get_year_hepos(birthdatetime):
        start_year = (birthdatetime.year - 3) % 60
        hs_pos = start_year % 10
        if hs_pos == 0:
            hs_pos = 10
        gb_pos = start_year % 12
        if gb_pos == 0:
            gb_pos = 12
        year_hepos = [hs_pos, gb_pos]
        return year_hepos

    def get_birth_time_epos(birthdatetime):
        if birthdatetime.hour in range(23, 1):
            return 1
        elif birthdatetime.hour in range(1, 3):
            return 2
        elif birthdatetime.hour in range(3, 5):
            return 3
        elif birthdatetime.hour in range(5, 7):
            return 4
        elif birthdatetime.hour in range(7, 9):
            return 5
        elif birthdatetime.hour in range(9, 11):
            return 6
        elif birthdatetime.hour in range(11, 13):
            return 7
        elif birthdatetime.hour in range(13, 15):
            return 8
        elif birthdatetime.hour in range(15, 17):
            return 9
        elif birthdatetime.hour in range(17, 19):
            return 10
        elif birthdatetime.hour in range(19, 21):
            return 11
        elif birthdatetime.hour in range(21, 23):
            return 12
        return 1

    def get_self_palace_epos(birthdatetime, isleap):

        month_position = birthdatetime.month
        hour_position = get_birth_time_epos(birthdatetime)

        #檢查是否為閏月
        if isleap == True:
            if Zwsetting.intercalary_month == 2:
                month_position += 1
            elif Zwsetting.intercalary_month == 3:
                if birthdatetime.day > 15:
                    month_position += 1
        # 直接將月份 +3 的原因是: +2 是為了將寅起調整成子起,另外的 +1 是因為計算時間時本格也算一次,所以 +1 調整回來。
        position = ( month_position + 3 - hour_position )%12
        position = 12 if position == 0 else position

        return position

    def get_body_palace_epos(birthdatetime, isleap):
        
        month_position = birthdatetime.month
        hour_position = get_birth_time_epos(birthdatetime)
        
        #檢查是否為閏月(先不用管閏十二月,最接近的兩年 1889年,2500年)
        if isleap == True:
            if Zwsetting.intercalary_month == 2:
                month_position += 1
            elif Zwsetting.intercalary_month == 3:
                if birthdatetime.day > 15:
                    month_position += 1

        # 直接將月份 +1 的原因是: +2 是為了將寅起調整成子起,另外的 -1 是因為計算時間時本格也算一次,所以 -1 調整回來。
        position = ( month_position + 1 + hour_position )%12
        position = 12 if position == 0 else position
        return position

    def get_yin_hpos(birthdatetime):
        start_year = (birthdatetime.year - 3) % 60
        hs_pos = start_year % 10
        if hs_pos == 0:
            hs_pos = 10
        self_hpos = ((1+hs_pos*2) % 10)
        return self_hpos

    def get_earth(x,y): ## 地支只能在 1-12 之間整數,x是目前位置,y是順數多少宮位(y為負則是逆數)
        result = (x + y) % 12        # 如果結果不在 1 到 12 之間,則進行調整
        while result <= 0:
            result += 12
        #print(x,y,result)    
        return result
    
    #chart_data = solar_year +'/'+  solar_month +'/'+ solar_day +'/'+ str(time_hour)+':'+str(time_min)+'/'+str(gender)
    #print(str(chart_data))

    solar_birth_datetime = datetime(int(solar_year), int(solar_month), int(solar_day), time_hour, time_min)

    #夜子時設定檢查
    if zi_adjust == 2 and time_hour >= 23 :
        solar_birth_datetime = solar_birth_datetime + timedelta(days=1)

    # 跳過 農曆轉換
    #lunar = Zwbase.get_lunar_datetime(solar_birth_datetime)
    #lunar_birth_datetime = LunarDatetime(lunar.lunarYear, lunar.lunarMonth, lunar.lunarDay, solar_birth_datetime.hour, solar_birth_datetime.minute, lunar.isleap)

    # 取得生辰年干支位置
    year_hepos = get_year_hepos(solar_birth_datetime)

    # 取得陰陽性別位置
    #   性別
    if gender == 2:
        gender_pos = 2
    else:
        gender_pos = 3
        
    #   陰陽
    yin_yang_pos = 0 if year_hepos[0] % 2 == 1 else 1


    # 取得生辰地支位置
    birth_time_epos = get_birth_time_epos(solar_birth_datetime)

    # 取得命宮地支位置
    self_palace_epos = get_self_palace_epos(solar_birth_datetime, False) ## 還沒有做 閏年 處理 lunar.isleap

    # 取得寅宮天干位置
    yin_hpos = get_yin_hpos(solar_birth_datetime)

    # 取得命宮天干位置
    #   - 計算命宮-寅宮順向距離
    self_yin_dist = 0
    if self_palace_epos >= 3:
        self_yin_dist = self_palace_epos - 3
    else:
        self_yin_dist = self_palace_epos + 9
    #   - 計算命宮天干位置
    self_palace_hpos = 0
    if (self_yin_dist + yin_hpos) > 10:
        self_palace_hpos = (self_yin_dist + yin_hpos) - 10
    else:
        self_palace_hpos = self_yin_dist + yin_hpos


    # 取得身宮位置
    body_palace_epos = get_body_palace_epos(solar_birth_datetime, False)

    # 取得五行局
    fiveway_param_1 = int(( self_palace_hpos + 1) / 2  if self_palace_hpos % 2 == 1 else self_palace_hpos / 2 )
    fiveway_param_2 = int(( self_palace_epos + 1) / 2  if self_palace_epos % 2 == 1 else  self_palace_epos / 2 )
    fiveway_pos = fiveoldsong[(fiveway_param_1 - 1) * 6 + fiveway_param_2 - 1]

    # 取得紫微星位置
    ziwei_pos = ziwei_table[(fiveway_pos -2) * 30 + int(solar_day)-1] ## lunar.lunarDay - 1

    # 取得天府星位置
    tianfu_pos = tianfu_table[ziwei_pos-1]

    outstr=f'用戶命盤上的紫微在:{earth_table[ziwei_pos-1]}宮,用戶命宮在:{earth_table[self_palace_epos-1]}宮'

    # 14 主星
    s_table = ['E','紫微','天機','太陽','武曲','天同','廉貞','天府','太陰','貪狼','巨門','天相','天梁','七殺','破軍']

    ming_table[ziwei_pos]=s_table[1]
    ming_table[get_earth(ziwei_pos,-1)]=s_table[2]
    ming_table[get_earth(ziwei_pos,-3)]=s_table[3]
    ming_table[get_earth(ziwei_pos,-4)]=s_table[4]
    ming_table[get_earth(ziwei_pos,-5)]=s_table[5]
    ming_table[get_earth(ziwei_pos,-8)]=s_table[6]

    ming_table[tianfu_pos]=ming_table[tianfu_pos] + s_table[7]
    ming_table[get_earth(tianfu_pos,1)]=ming_table[get_earth(tianfu_pos,1)] + s_table[8]
    ming_table[get_earth(tianfu_pos,2)]=ming_table[get_earth(tianfu_pos,2)] + s_table[9]
    ming_table[get_earth(tianfu_pos,3)]=ming_table[get_earth(tianfu_pos,3)] + s_table[10]
    ming_table[get_earth(tianfu_pos,4)]=ming_table[get_earth(tianfu_pos,4)] + s_table[11]
    ming_table[get_earth(tianfu_pos,5)]=ming_table[get_earth(tianfu_pos,5)] + s_table[12]
    ming_table[get_earth(tianfu_pos,6)]=ming_table[get_earth(tianfu_pos,6)] + s_table[13]
    ming_table[get_earth(tianfu_pos,10)]=ming_table[get_earth(tianfu_pos,10)] + s_table[14]

    ming_star.value = ming_table[self_palace_epos]
    # 要處理命宮空宮的狀況
    if len(ming_star.value) == 0:
        if self_palace_epos <= 6:
            ming_star.value = '空' + ming_table[self_palace_epos+6]
            outstr = outstr + f'\n命宮主星是:空宮,需要借星( {ming_table[self_palace_epos+6]} )'
        else:
            ming_star.value = '空' + ming_table[self_palace_epos-6]
            outstr = outstr + f'\n命宮主星:是空宮,需要借星( {ming_table[self_palace_epos-6]} )'
    else:
        # outstr = outstr + f'\n==> {ming_table}'
        outstr = outstr + f'\n命宮主星是:( {ming_table[self_palace_epos]} )'

    # 五行局為{fiveway[fiveway_pos-2]},

    return outstr

def get_envkey():
    from dotenv import load_dotenv, find_dotenv
    _ = load_dotenv(find_dotenv()) # read local .env file
    openai.api_key = os.environ['OPENAI_API_KEY']
    print(openai.api_key)
    if openai.api_key:
       DESKTOP_KEY = openai.api_key 
    print(DESKTOP_KEY)

if localrun:
    get_envkey()

# 定義地支對應的時間區間
z_mapping = {
        "1": "子",
        "2": "丑",
        "3": "寅",
        "4": "卯",
        "5": "辰",
        "6": "巳",
        "7": "午",
        "8": "未",
        "9": "申",
        "10": "酉",
        "11": "戌",
        "12": "亥",
        "0": "夜子"
    } 

## AI 建議
def get_advice(API_KEY, model="gpt-3.5-turbo-16k"):
    if API_KEY:
        openai.api_key = API_KEY
    else:
        openai.api_key = DESKTOP_KEY
    # print(openai.api_key)

    if openai.api_key == False:
        output = '你需要有 OPENAI 的 API 金鑰,我才能提供您建議。(我們程式不會儲存你的金鑰)有了建議後再請你評分,謝謝。\
        \n\n(請參考 https://ithelp.ithome.com.tw/articles/10333740 取得 OPENAI 的 API 金鑰)'
        return output
        
    # 指定 JSON 檔案路徑
    json_file_path = 'stars14.json'

    # 讀取 JSON 檔案
    with open(json_file_path, 'r') as json_file:
        # 使用 json.load() 方法將 JSON 檔案轉換為 Python 物件
        myData = json.load(json_file)
    # 現在,myData 變數包含了 JSON 檔案的內容


    def get_data(star_name): ##
        msum = ''
        gw_main_star = ''
        print(star_name)
        for i in range(0, 14):
            if myData[i]['命宮星象'] == star_name:
                msum = msum + myData[i]['整體描述']
                print(msum)
                #gw_main_star = gw_main_star + myData[i]['正面特質'] + myData[i]['負面特質']
                gw_main_star = gw_main_star + myData[i]['正面特質']
                gw_main_star = gw_main_star + myData[i]['負面特質']
                #print(gw_main_star)
                break
        return msum,gw_main_star
    
    print(len(ming_star.value)) # 如果是4就有兩個主星,0就是沒有主星
    if len(ming_star.value) == 2:
        msum,gw_main_star = get_data(ming_star.value)
    elif len(ming_star.value) == 4:
        # '你的命宮有雙主星:\n\n'
        first_star = ming_star.value[:2]
        second_star = ming_star.value[2:4]
        print(f'first_star = {first_star} second_star = {second_star}')
        msum_tmp = ''
        gw_main_star_tmp = ''
        msum_tmp,gw_main_star_tmp = get_data(first_star)
        msum,gw_main_star = get_data(second_star)
        msum = '<你的命宮有雙主星>\n\n' + msum_tmp + '\n\n' + msum
        gw_main_star = gw_main_star_tmp + '\n' + gw_main_star
        #
    elif len(ming_star.value) == 5:
        # '你的命宮沒有主星:\n\n'
        first_star = ming_star.value[1:3]
        second_star = ming_star.value[3:5]
        print(f'first_star = {first_star} second_star = {second_star}')
        msum_tmp = ''
        gw_main_star_tmp = ''
        msum_tmp,gw_main_star_tmp = get_data(first_star)
        msum,gw_main_star = get_data(second_star)
        msum = '<你的命宮沒有紫微主星(我們向遷移宮借星)>\n\n' + msum_tmp + '\n\n' + msum
        gw_main_star = gw_main_star_tmp + '\n' + gw_main_star
        #
    else:
        print("DATA ERROR!!!")
        #
        #
    
    print(ming_star.value,"===",gw_main_star,"#####")

    messages = [{"role": "system", "content": "你是一個心理學權威,當接收到一段關於人格特質的描述時,請以一個專業的心理諮商師的身分進行以下回應。(但你不可以自稱是心理師或心理學權威) \
            1. 選出3~4個正向特質給予肯定,帶領使用者欣賞自身優點 \
            2. 選出2~3個負向特質,以包容的態度,給予適當的建議,點出問題核心。 \
            3. 從正向特質中找尋可以改善負向特質的方法,提出有建設性的方案。 \
            4. 鼓勵自發性地做出改變及經常自省,將負向特質轉化成優勢。同時強調不需操之過急,設定階段性目標,逐步實踐。 \
            5. 提醒他是個獨特的人,就算無法改變也是相當珍貴的人。 \
            6. 鼓勵對方如果內心仍有困擾,多與可信賴的重要他人商量、建立良好關係。"},
    #            你是一個心理學權威,當接收到一段關於人格特質的描述時,請以一個專業的心理諮商師的身分,約500字的長度,針對正向特質給予肯定,帶領使用者欣賞自身優點;\
    #            針對負向特質則以包容的態度,約1500字的長度,給予適當的建議,並鼓勵自發性地做出改變及經常自省,將負向特質轉化成自己的優勢。最後再給予約200字的總結。\
    #            請你用 traditional Chinese 回答
    #            {"role": "user", "content": f'我的人格特質以紫微斗數星象來推論是“{gw_main_star}”. 請替我依照這些人格特質,並根據 Myers-Briggs Type Indicator (MBTI) 人格分析學說,一條一條的幫我解析?'},]
    #            {"role": "user", "content": f'我的人格特質以紫微斗數星象來推論是“{gw_main_star}”. 請替我依照這些人格特質,並根據 16 Personality Factors 人格分析工具,一條一條的幫我分析?'},]
    #            {"role": "user", "content": f'我的人格特質以紫微斗數星象來推論是“{gw_main_star}”. 請替我依照這些人格特質,並根據 OCEAN 五大人格分析系統,一條一條的幫我分析?'},]
                {"role": "user", "content": f'用戶的人格特質以紫微斗數星象來推論是“{gw_main_star}”. 請給他一些待人處事的建議?'},]
    # OCEAN 五大人格特質
    response = openai.chat.completions.create(
        model=model,
        max_tokens=4096,
        messages=messages,
        temperature=0.1, # this is the degree of randomness of the model's output
    )
    returndata = '紫微斗數全書上面說:\n\n' + msum + '\n\n' + response.choices[0].message.content
    if API_KEY:
        ming_feedback.info = 'YES'
        ming_feedback.value = returndata

    return returndata 

def GWAI(year, month, day, btime, sex) -> datetime:
    dt_date1 = datetime(int(year), int(month), int(day))
    date_lunar = ZhDate.from_datetime(dt_date1)
    bstr = str(date_lunar)

    # 發現有用戶會在時間輸入時,輸進全型的分號
    if ':' in btime:
        hour = int(btime.split(":")[0])
    else:
        hour = int(btime.split(":")[0])

    if hour >= 23:
        z = 0
    else:
        z = int((hour + 1) / 2) + 1
    result=z_mapping[str(z)]
    output=(bstr.replace('农历','農曆') + " " + result + "時")

    import re
    match = re.search(r'(\d+)年(\d+)月(\d+)日', output)

    # 發現有些時間輸入後,會是閏月的狀況
    if match:
        my_year = match.group(1)
        my_month = match.group(2)
        my_day = match.group(3)
        print("- leap no -")
    else:
        match = re.search(r'(\d+)年闰(\d+)月(\d+)日', output)
        my_year = match.group(1)
        my_month = match.group(2)
        my_day = match.group(3)
        print("- leap yes -")

    pssex = 2
    if sex == '男' or sex == '男生' or sex == 'Male' or sex == 'male' or sex == 'M' or sex == 'm' or sex == 'Boy' or sex == 'boy'  or sex == '1':
        pssex = 1

    print(output)
    print('<<',my_year,my_month,my_day,pssex,'>>')
    output2=gen_chart(int(my_year), int(my_month), int(my_day), hour, int(30), int(pssex))
    return output,output2

def disp_prompt():
    output = '''你是 ChatGPT, a large language model trained by OpenAI, based on the GPT-4 architecture.
我打算用傳統中文 traditional Chinese 給你一個叫“排龍珠”的任務,結果請你也用 traditional Chinese 回答。
這個任務有以下步驟,請一步一步依循這些步驟去完成
步驟1:你需要用戶給你一些數值,你必須依賴這些數值去計算最後的結果
步驟2:你需要的數值有年、月、日、時。還有性別。
步驟3:你需要的數值,年的部分,它是 1940 到 2040 間的 int 整數。
步驟4:你需要的數值,月的部分,它是 1 到 12 間的 int 整數。
步驟5:你需要的數值,日的部分,它是 1 到 30 間的 int 整數,我們會特別稱它叫排盤日。
步驟6:你需要的數值,時的部分,它是 1 到 12 間的 int 整數。
步驟7:你需要的數值,性別的部分,男性是以整數 1 表示,女性是以整數 2 表示。
步驟8:以下是三個正確的數值範例。1992/11/28/12/2。1983/4/3/9/1。1977/6/2/7/1。
步驟9:我們定義『盤箱串』是一個有12個箱子的結構體,箱子從編號1連接編號2,編號3,編號4,一直到編號12。然後編號12會接到編號1,形成一個圓圈的結構體『盤箱串』。
步驟10:『盤箱串』上的12個箱子,每個箱子外面有貼一張標籤,該標籤只可以是1到10之間的整數,而且他們是依序排列的1,2,3,...,10,10的後面接著1,2,3...。你知道如果我從編號3的箱子開始貼標籤1,那編號12的箱子的標籤數字就是10,那編號1的箱子的標籤數字就是1,那編號2的箱子的標籤數字就是2。
步驟11:接下來,我們要給某一個箱子貼上彩虹紙帶。這個貼彩虹紙帶箱子的選擇方式是,把月的數值,加上14,然後減去時的數值,再將結果加1,得到的數字再取其與12的餘數,如果餘數等於0,就加上12,以上計算的數值將落在1與12之間,就是貼彩虹紙帶箱子的編號(B)。
步驟12:接著,我們可以從用戶提供的年這個數值,去算出編號3的箱子外面的標籤的數字(K)。將年這個數值除以10得到的餘數,會是0到9之間的正整數。
這個數字是4或9的時候,(K)會是3。
這個數字是5或0的時候,(K)會是5。
這個數字是6或1的時候,(K)會是7。
這個數字是7或2的時候,(K)會是9。
這個數字是8或3的時候,(K)會是1。
步驟13:我們“排龍珠”任務要算的是有貼上彩虹紙帶那個箱子的『五行局』。你必須有貼彩虹紙帶的箱子的編號(B),還有貼彩虹紙帶的箱子的標籤數字(A),才能繼續。
步驟14:如果編號3的箱子外面的標籤數字算出來為(N)。我們要算出貼上彩虹紙帶那個箱子外面的標籤數字(A),這個數字(A)如果大於或等於3,它就等於貼彩虹紙帶的箱子編號(B) - 3 + 編號3的箱子外面的標籤數字(N)。如果這個數字如果小於3,它就等於貼彩虹紙帶的箱子編號(B) - 1 + 編號3的箱子外面的標籤數字(N)。
步驟15:我們現在要算出貼上彩虹紙帶那個箱子外面的標籤數字。我們可以根據貼彩虹紙帶的箱子編號(B)與箱子上的標籤數字(A),再去算出貼彩虹紙帶的箱子的『五行局』這個數值。
步驟16:將(((A+1)/2)-1)的結果,只取商數,然後乘以6,得到C。然後 ((B+1)/2)的結果,只取商數為D。(C+D)得出的數字(M),以這個數字(M)去查以下陣列表格(這個陣列表格不是從0而是從1開始索引排序的):[ 4, 2, 6, 4, 2, 6, 2, 6, 5, 2, 6, 5, 6, 5, 3, 6, 5, 3, 5, 3, 4, 5, 3, 4, 3, 4, 2, 3, 4, 2 ]。這樣查表格所得到的數字就是有貼上彩虹紙帶那個箱子『五行局』的數值(F)。
步驟17:接下來,我們要把一顆『龍珠』放進箱子裡,要放『龍珠』這個星星的箱子,必須滿足以下一些條件。
步驟18:先把(用戶輸入的“排盤日”數值)除以(F)。我們把這個結果分成商(z),餘數(y),來記錄。
如果y等於0時,我們取商(z)這個值。
如果y不等於0時,把(F)乘以(商(z)+1)去減掉(用戶輸入日的數值),得到ㄧ個值,我們叫它(x)。(商(z)+1),我們叫它(k)
步驟19:如果 x 是奇數,那麼(k)這個值要減掉 x
步驟20:如果 x 是偶數,那麼(k)這個值要加上 x
步驟21:依步驟19或步驟20,將(k)算出來
步驟22:如果 (k) >= 0 ,這個箱子編號(MS)	=(k) + 2
步驟23:如果 (k) < 0 ,這個箱子編號(MS)=(k) + 14
步驟24:以上計算好後,我們就可以知道『龍珠』該放進去箱子是(MS)
步驟25:最後請告訴用戶“排龍珠”任務的結果,包括
貼彩虹紙帶的箱子編號(B)是多少
該箱子的標籤數字(A)是多少
貼上彩虹紙帶那個箱子『五行局』的數值(F)是多少
有『龍珠』的箱子的編號(MS)是多少
步驟26:完成。'''

    return output

def save_feedback(x,savedata):
    import sqlite3

    conn = sqlite3.connect('savedata.db')
    c = conn.cursor()

    if ming_feedback.info != '':
        output = f'謝謝您給我們 {x} / 5 分的評分,我把評分存起來了,謝謝你的評分!'
        ming_feedback.info = ''
        td = datetime.now().strftime('%Y-%m-%d, %H:%M:%S')
        ming_feedback.value = savedata + '\n\n' + ming_feedback.value
        print(td,ming_feedback.value)
        c.execute(f'''INSERT INTO USERFEEDBACK (FEEDBACK,SCORE,MINGSTAR,SAVEDATE) \
              VALUES ( "{ming_feedback.value}", {x}, "{ming_star.value}", "{td}" )''')
        conn.commit()
    else:
        output = '你需要有 OPENAI 的 API 金鑰,我才能提供您建議(我們程式不會儲存你的金鑰)。有了建議後再請你評分,謝謝。\
        \n\n(請參考 https://ithelp.ithome.com.tw/articles/10333740 取得 OPENAI 的 API 金鑰)'
   
    conn.close()
    print(f'User given score = {x} ',savedata)    
    return output


# 建立 components
year = gr.Textbox(
    label="生年",
    info="輸入你的西元出生年份",
    placeholder="Input your birth year here...")

month = gr.Textbox(
    label="生月",
    info="輸入你的出生月份",
    placeholder="Input your birthday month here...",)

day = gr.Textbox(
    label="生日",
    info="輸入你的出生日子",
    placeholder="Input your birthday day here...",)

btime = gr.Textbox(
    label="生時",
    info="輸入你的出生時間 HH:MM (幾點及約略幾分即可,請用24小時制)",
    placeholder="Input your birth time here...",)

sex = gr.Textbox(
    label="性別",
    info="輸入你是男生或女生",
    placeholder="Input you are male or female here...",)

output_gwai = gr.Textbox(
    value="",
    label="你的農曆生日及出生時辰",
    info="這是從西元換算出的農曆生日及出生時辰",
    placeholder="Date & Time")

output2_gwai = gr.Textbox(
    value="",
    label="你的紫微斗數命宮星象",
    info="這是你的紫微斗數命盤上,命宮裡的主星的資訊",
    placeholder="Stars in your master plate.")

advice = gr.Textbox(
    label="輸出視窗",
    info="根據你需求的 LLM 輸出結果",
    placeholder="Ouput Text here...",
    lines=5,)

btn = gr.Button(
    value="計算農曆生日及八字時辰",
    variant="primary", scale=1)

btn_advice  = gr.Button(
    value="AI 紫微的人生建議",
    variant="primary", scale=2)

btn_chat = gr.Button(
    value="教 LLM 紫微排盤的 Prompt",
    variant="primary", scale=1)

key_box = gr.Textbox(
    label="輸入你的 API 金鑰",
    info="You have to provide your own OPENAI_API_KEY for this app to function properly",
    placeholder="Type OpenAI API KEY here...",
    type="password")

btn_feedback = gr.Button(
    value="送出評分",
    variant="primary", scale=1)

ming_star = gr.Textbox(
    label="命宮主星",
    info="",
    placeholder="",
    value="MINGSTAR")

ming_feedback = gr.Textbox(
    label="回饋評分",
    info="",
    placeholder="",
    value="MINGFB")

ft = gr.Slider(
    minimum=1,
    maximum=5,
    step=1,
    value=5,
    label="請評分(1 - 5 分)",
    info="你覺得我們的人生建議是否貼切,是否有助益呢?請給我們評分(劣)1 - 5 分(優)。")

with gr.Blocks() as demo:
    gr.Markdown("""
    # AI 紫微
    有沒有可能?! - 你的農曆出生時辰,已經決定了你的基本個性與處事態度\n\n
    讓 AI 根據你的出生時間,依照紫微斗數全書上的古法,計算出你的命盤星象,並給你一些心理學上的人生建議
    """)
    with gr.Column():
        with gr.Row():
            year.render()  # 顯示年
            month.render() # 顯示月
            day.render() # 顯示日
            btime.render() # 顯示時
            sex.render() # 顯示性別
        
        with gr.Row():
            output_gwai.render() # 顯示農曆生日欄
            output2_gwai.render()

        btn.render() # 顯示農曆生日值結果
        btn.click(fn=GWAI, 
                     inputs=[year, month, day, btime, sex], 
                     outputs=[output_gwai,output2_gwai])
        advice.render() # 顯示AI建議結果的文字框
        
        with gr.Row(): 
            key_box.render() # 顯示API金鑰輸入框
            btn_advice.render() # 顯示AI建議按鈕
            btn_advice.click(fn=get_advice, inputs=[key_box], outputs=advice)
            btn_chat.click(fn=disp_prompt, outputs=advice)
            btn_chat.render() # 顯示紫微聊天室按鈕
    
        with gr.Row():
            ft.render()
            btn_feedback.render()
            btn_feedback.click(fn=save_feedback, inputs=[ft,output_gwai], outputs=advice)

demo.launch()