iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
確定準備好材料了,繼續組裝積木吧!

為了讓占卜得以實現,立刻接續昨天的進度往下進行!


為占卜加上洗牌儀式

繼續疊上 Day 12 完成的洗牌機制,並進行抽牌。

    # ===== 加入洗牌機制 =====
    deckService = DeckService()
    # 預先洗牌
    deck = deckService.shuffle_and_cut(deck)
    # 攤牌洗牌
    deck = deckService.spread_shuffle(deck)
    # 將牌收攏
    deck = deckService.gather_deck(deck)
    # 切牌
    deck = deckService.split_and_merge(deck)
    # 逆時針調整牌的方向
    deck = deckService.turn_counterclockwise(deck)
    # 抽三張
    cards_1 = deck[:3] # 抽前三張
    cards_2 = random.sample(deck, 3)  # 抽隨機三張
    # 檢視抽牌結果
    print(f"cards_1={cards_1}, cards_2={cards_2}")
  • 執行測試
    https://ithelp.ithome.com.tw/upload/images/20251006/20168437yMTtAZi9hq.png

  • 輸出結果

    // cards_1
    [
      {"id": "MA_07_Chariot",           "position": "↓"},
      {"id": "MI_2_Two of Wands",       "position": "↑"},
      {"id": "MI_8_Eight of Pentacles", "position": "↑"}
    ]
    // cards_2
    [
      {"id": "MI_Queen_Queen of Wands", "position": "↑"},
      {"id": "MI_10_Ten of Swords",     "position": "↓"},
      {"id": "MI_9_Nine of Cups",       "position": "↑"}
    ]
    

    不知道是不是湊巧,兩種方式抽出來都是兩正位一逆位...
    總之先確認了洗牌後抽選的隨機性。

  • 接著將牌翻出來
    根據抽到的塔羅牌 ID 取得關鍵字和牌面說明

# 抽三張
cards_1 = deck[:3] # 抽前三張
cards_2 = random.sample(deck, 3)  # 抽隨機三張
# 檢視抽牌結果
print(f"cards_1={cards_1}, cards_2={cards_2}")

# ===== 取得塔羅牌資訊 =====
cards_1_info = []
card_2_info = []
for i in range(3):
    cards_1_info.append(tarot_by_id.get(cards_1[i]['id']))
    card_2_info.append(tarot_by_id.get(cards_2[i]['id']))
print(f"cards_1_info={cards_1_info}, card_2_info={card_2_info}")
  • 執行結果
    https://ithelp.ithome.com.tw/upload/images/20251006/20168437ze54lZfB14.png

整理一下

為了讓整個程式邏輯好讀一些,將現有流程整理成更好理解的結構

  • 將洗牌和抽牌各自整合成 function
    def shuffle(self, deck):
        """
        完整的洗牌流程
        """
        # 預先洗牌
        deck = self.shuffle_and_cut(deck)
        # 攤牌洗牌
        deck = self.spread_shuffle(deck)
        # 將牌收攏
        deck = self.gather_deck(deck)
        # 切牌
        deck = self.split_and_merge(deck)
        # 逆時針調整牌的方向
        return self.turn_counterclockwise(deck)
    
    def draw_card(self, deck, count, random_pick=True):
        """
        從洗好的塔羅牌裡抽選,預設隨機
        """
        if random_pick:
            return random.sample(deck, count)
        else:
            return deck[:count]
    
  • 根據正/逆位取得塔羅牌資訊
    # ===== 取得塔羅牌資訊 =====
        cards_info = []
        for i in range(3):
            card_info = tarot_by_id.get(cards[i]['id'])
            card = {
                'card_id': card_info['id'],
                'card_name': card_info['name_zh'],
                'story': card_info['story']
                }
            if cards[i]['position'] == '↑':
                card['position'] = 'upright'
                card['keyword'] = card_info['upright_meta']['keywords']
            else:
                card['position'] = 'reversed'
                card['keyword'] = card_info['reversed_meta']['keywords']
    
            cards_info.append(card)
        print(f"cards_info={cards_info}")
    
  • 執行測試
    https://ithelp.ithome.com.tw/upload/images/20251006/20168437uy3rcGcLhh.png
[
  {
    "card_id": "MA_21_World",
    "card_name": "世界",
    "story": "世界牌中央是一名舞動的人物,她雙腿交叉,雙手各持一根魔杖,象徵平衡與進化。這份充實與統一並非靜止,而是永恆的流動與轉化。人物被綠色花環環繞,象徵成功;外圍的紅色絲帶形成無限符號,寓意永恆與無窮。四角的四個形象與命運之輪中的相同:天蠍、獅子、水瓶與金牛,分別代表宇宙的四個角落、四大元素與四位福音傳道者。整體構圖展現出萬物能量的融合與和諧。",
    "position": "upright",
    "keyword": ["完成", "成就", "成就感", "歸屬感", "整體性", "和諧"]
  },
  {
    "card_id": "MI_Queen_Queen of Wands",
    "card_name": "權杖皇后",
    "story": "權杖皇后所描繪的形像是一位女王驕傲地坐在寶座上,面朝前方,這是力量和火焰的明確象徵。她左手捧著一朵向日葵,寶座上還雕刻著向日葵的形象——寓意幸福、滿足、生育。她的右手拿著她的權杖,權杖開始開花,象徵著生命。在她的積極方面,權杖皇后可以與忠誠、寄託和溫暖聯繫在一起。腳下的黑貓暗示了她隱藏的一面,這在傳統上是巫術和神秘主義的象徵,但也表明她擁有深刻的直覺把握能力。",
    "position": "upright",
    "keyword": ["自信", "熱情", "堅定", "社交", "有魅力", "活潑", "樂觀"]
  },
  {
    "card_id": "MI_6_Six of Wands",
    "card_name": "權杖六",
    "story": "權杖六塔羅牌描繪了一個男人,他的頭上戴著勝利的花環。他被描繪成騎著馬穿過歡呼的人群。馬是白色的,這是眾所周知的力量、純潔和成功的象徵。人群在那裡表明公眾對騎馬人所取得的成就的認可。該男子所攜帶的權杖上還繫著一個花圈,試圖進一步強調他的成功。這個人對所有這些關注並不害怕,也不害羞,而是為自己的成就感到自豪。對此,他周圍的人群反應出歡快和熱情。",
    "position": "upright",
    "keyword": ["成功", " 勝利", "獎勵", "認可", "讚美", "讚譽", "驕傲"]
  }
]

呼叫 Bedrock

洗牌、抽牌的功能都完成了,接下來就該處理最核心的功能:讓 AI 解讀抽出的牌面

  • 現在還沒有加入對話功能,先把要提問的內容直接寫進 prompt:
    請根據抽到的塔羅牌,解讀近三個月的財務運勢。
    
  • BedrockService
    class BedrockService:
    
        def tarot_reading_local(self, system_role, cards):
            """
            從本地端呼叫 Bedrock 服務
            system_role: 要提供給模型的角色設定
            """
            session = boto3.Session(profile_name="dev-call-bedrock")
            client = session.client("bedrock-runtime", region_name="ap-northeast-1")
    
            prompt = f"""
            請根據抽到的塔羅牌,解讀近三個月的財務運勢。
            {cards}
            """
            print(prompt)
    
            body = {
                "system": system_role,
                "anthropic_version": "bedrock-2023-05-31",
                "messages": [
                    {"role": "user", "content": [{"type": "text", "text": prompt}]}
                ],
                "max_tokens": 2000,
                "temperature": 0.7
            }
    
            response = client.invoke_model(
                modelId="arn:aws:bedrock:ap-northeast-1:590184072539:inference-profile/apac.anthropic.claude-3-7-sonnet-20250219-v1:0",
                body=json.dumps(body)
            )
    
            output = json.loads(response['body'].read())
            return output['content'][0]['text']
    

之所以特別註解「本地端呼叫」,是因為在本地端運行時,使用的是透過 IAM Identity Center 登入取得的 SSO token。
但當程式佈署上雲端環境,這個方式是 一定 會直接失效的。

在 Lambda 上運行的程式,與現在測試的版本有兩個最大的差異:

  • 不須引入 boto3
    在 Lambda 執行的環境已經直接支援,不需要另外寫入 requirements.txt

  • 驗證方式為 IAM Role,程式端不再需要讀取 token,可以直接寫成:

    client = boto3.client("bedrock-runtime", region_name="ap-northeast-1")
    
  • 執行結果
    https://ithelp.ithome.com.tw/upload/images/20251006/20168437Cy7bNKVsmp.png

  • 生成結果評估
    流暢度:文字結構嚴謹、語氣平衡。
    語氣:理性且溫和,沒有過度正向或負向的誇張敘述。
    故事性:明確組織出牌義之間的連貫脈絡,內容兼顧牌面象徵和現實狀況的解讀。
    引導性:以成長與反思為核心主題。

整體而言沒有給人瞎扯或是一看就很假的感受,還算滿意!


最後附上完整的 AI 生成結果:Day 23. AI 生成結果


上一篇
Day 22. 停下來喘口氣很重要
系列文
科學的盡頭是玄學?AI占卜小助手與知識庫驗證23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言