確定準備好材料了,繼續組裝積木吧!
為了讓占卜得以實現,立刻接續昨天的進度往下進行!
繼續疊上 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}")
執行測試
輸出結果
// 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}")
為了讓整個程式邏輯好讀一些,將現有流程整理成更好理解的結構
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}")
[
{
"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": ["成功", " 勝利", "獎勵", "認可", "讚美", "讚譽", "驕傲"]
}
]
洗牌、抽牌的功能都完成了,接下來就該處理最核心的功能:讓 AI 解讀抽出的牌面
。
請根據抽到的塔羅牌,解讀近三個月的財務運勢。
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")
執行結果
生成結果評估
流暢度:文字結構嚴謹、語氣平衡。
語氣:理性且溫和,沒有過度正向或負向的誇張敘述。
故事性:明確組織出牌義之間的連貫脈絡,內容兼顧牌面象徵和現實狀況的解讀。
引導性:以成長與反思為核心主題。
整體而言沒有給人瞎扯或是一看就很假的感受,還算滿意!
最後附上完整的 AI 生成結果:Day 23. AI 生成結果