File size: 27,342 Bytes
2842173
 
 
 
 
 
 
 
 
 
0758717
 
 
 
 
2842173
cc7328c
 
 
 
2842173
 
 
cc7328c
 
 
b4251f4
 
 
4fc7350
80f4b08
 
 
cc7328c
1ced91c
 
c4d4857
 
 
 
 
 
2842173
c4d4857
4fc7350
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
 
 
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
 
 
c4d4857
 
 
 
 
 
2842173
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
c4d4857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c4d4857
 
 
1ced91c
 
 
 
 
 
 
 
 
 
 
0121f83
80f4b08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b4251f4
 
c01e3fe
e8e1c5a
0121f83
 
 
 
f4fafda
b4251f4
4fc7350
b49206c
 
 
4fc7350
 
 
 
 
 
 
 
 
 
e8e1c5a
 
 
 
 
4fc7350
 
 
 
 
f4fafda
4fc7350
 
2842173
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0121f83
4fc7350
 
 
 
 
 
9d170ee
cc7328c
 
 
9d170ee
cc7328c
cb97198
 
 
 
 
cc7328c
cb97198
 
 
 
 
 
f4fafda
4fc7350
 
2498233
4fc7350
 
b4251f4
1ced91c
80f4b08
 
 
2c0b4ad
e8e1c5a
2c0b4ad
 
 
 
 
 
80f4b08
 
b4251f4
1ced91c
80f4b08
1ced91c
c4d4857
 
 
 
2c0b4ad
c4d4857
 
 
 
839f058
 
 
 
 
 
 
c4d4857
4fc7350
 
 
 
e8e1c5a
4fc7350
 
 
1ced91c
b4251f4
2842173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc7350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2498233
4fc7350
 
 
 
 
 
 
 
 
2498233
4fc7350
 
 
 
 
b49206c
 
4fc7350
 
2498233
4fc7350
b4251f4
 
 
8697be1
 
e8e1c5a
77eed2b
b4251f4
8697be1
 
e8e1c5a
77eed2b
8697be1
 
 
e8e1c5a
77eed2b
 
80f4b08
77eed2b
80f4b08
77eed2b
 
 
 
e8e1c5a
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
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
## 這是 TAIA x H.I.T LLM線上共學社群的專題實作 6
#
# Copyright (C) 2023 Bob Yeh, Jinny Tsai
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
##
## AI 紫微
##
## 開發者:葉浩銘 Bob、蔡靜穎 Jinny 2024-03
##
## 利用在 TAIA x H.I.T 線上共學社群的 AI 課程學到的技術
## > prompt engineering
## > gradio
## > HuggingFace SPACE
## > OpenAI LLM
## 希望能透過開源,拋磚引玉,讓紫微斗數這門古老學問,可以在 AI 浪潮中更加發揚光大
##
## Note:
## GPT model="gpt-3.5-turbo-16k",若用 "GPT-4" 表現會更好
## 可以在你 local 的資料夾新增 .env 檔案,並在裡面寫入 API_KEY=你的 OpenAI API 金鑰,方便 local 測試
##
import os
import openai
import gradio as gr
import json
from zhdate import ZhDate
from datetime import datetime

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

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

#命宮主星是 ming_table[self_palace_epos]
zi_adjust = 2

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)

    # 取得生辰年干支位置
    year_hepos = get_year_hepos(solar_birth_datetime)
        
    #   陰陽
    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 檔案的內容

    # 處理性別
    global gender
    pssex = '男'
    if gender == 2:
        pssex = '女'

    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)口氣溫柔且堅定,不可自稱專家,請多舉例,並用繁體中文回覆。 \
                (2)請你以一個紫微斗數學者的角度,一條一條仔細閱讀對方的命宮主星資訊,再總結挑選3~4個正向人格特質及2~3個負向人格特質,去剖析這些特質對他的可能影響。 \
                (3)請你以一個諮商心理學者的角度,對前一段的正向人格特質進行肯定,並再針對前一段的2~3個負向特質提出改善建議。 \
                (4)最後請根據前面的改善建議,舉出 ‘實際例子’ 給對方,教他該如何增加自信、如何愛自己,若過於煩惱時要適當尋求協助等等。"},
                {"role": "user", "content": f'我的紫微斗數命宮主星資訊是:\n\n“{gw_main_star}“。\n\n請給我紫微斗數及諮商心理學,"學者"之角度,可提供之專業的回覆'},]
    try:
        response = openai.chat.completions.create(
            model=model,
            max_tokens=4096,
            messages=messages,
            temperature=0.01, # this is the degree of randomness of the model's output
        )
    except openai.APIError as e:
        # Handle the error
        print("An error occurred:", e)
        return e
        
    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)

    global gender
    # 發現有用戶會在時間輸入時,輸進全型的分號
    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

    gender = pssex
    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

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

1. 定命宮等十二宮

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

3. 定紫微星、天府星

4. 安十四主星

# 起紫微星訣算法
#
# - 六五四三二,酉午亥辰丑,
# - 局數除日數,商數宮前走;
# - 若見數無余,便要起虎口,
# - 日數小於局,還直宮中守。

'''


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="輸入你的西元出生年份(1900-2024)",
    placeholder="Input your birth year here...")

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

day = gr.Textbox(
    label="生日",
    info="輸入你的出生日子(1-30)",
    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="輸入你是男生(M)或女生(F)",
    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()