我的 OpenAI API 帳戶自去年再次儲值 5 美元後, 只做了少許生圖測試便晾在一邊, 轉眼已過了大半年, 為了避免一年使用期限到期沒用完被沒收, 打算拿 Oreilly "AI 應用程式開發" 這本書第三章的六個 App 專案來消耗掉.
此書的範例程式可在 GitHub 下載 :
本篇旨在測試第三章中的專案 1 : 打造一個新聞稿生成器, 書中範例原始碼參考 :
本系列全部測試文章索引參考 :
此專案的目的是建立一個 AI 應用程式, 可以指定文章長度, 語氣與風格來生成新聞稿. 書中範例程式使用了 typing.List 來進行類型提示 (Type Hinting), 例如 facts: List[str] 是告訴閱讀程式碼的人或 IDE : facts 這個參數應該是一個串列, 且這個串列裡面的每個元素都應該是字串. 不過, 這種用法在 Python 3.9 之後已經內建到 list 中了, 新寫法是 facts: list[str], 所以我將原始範例程式碼改寫為如下 :
# news_generator_1.py
from openai import OpenAI
from dotenv import dotenv_values
config=dotenv_values('.env')
openai_api_key=config.get('OPENAI_API_KEY')
client=OpenAI(api_key=openai_api_key)
def ask_gpt(
messages: list[dict[str, str]],
model: str = 'gpt-3.5-turbo'
) -> str:
try:
reply=client.chat.completions.create(
model=model,
messages=messages
)
return reply.choices[0].message.content or ''
except APIError as e:
return e.message
prompt_role='''You are an assistant for journalists.
Your task is to write articles, based on the FACTS that are given to you.
You should respect the instructions: the TONE, the LENGTH, and the STYLE'''
# 你是記者的助理.
# 你的任務是根據所提供的事實 (FACTS) 來撰寫一篇新聞稿.
# 文章需符合指定的語氣 (TONE), 長度 (LENGTH), 與風格 (STYLE).
def assist_journalist(
facts: list[str],
tone: str,
length_words: int,
style: str
) -> str:
"""根據傳入的事實、語氣, 長度與風格生成新聞稿"""
facts_str=", ".join(facts)
prompt=f'{prompt_role}\nFACTS: {facts_str}\nTONE: {tone}\nLENGTH: {length_words} words\nSTYLE: {style}'
return ask_gpt([{"role": "user", "content": prompt}])
# 執行範例
if __name__ == "__main__":
result=assist_journalist(
facts=[
'2026年東京櫻花預計在3月底滿開',
'上野公園是著名的賞櫻勝地,有超過1000棵櫻花樹',
'傍晚會有點燈活動,可以欣賞浪漫的夜櫻',
'請使用繁體中文撰寫'
],
tone='浪漫且活潑',
length_words=300,
style='旅遊部落格文章'
)
print(result)
此處兩個函式 assist_journalist() 與 ask_gpt() 的傳入參數都使用了類型提示語法以增加程式碼可讀性. 例如 ask_gpt() 中的 messages: list[dict[str, str]] 意思是 :
- messages 是一個串列, 裡面的每個元素都是字典.
- 字典的鍵與值都是字串, 例如 {"role": "user", "content": "hello"}
而 model: str = 'gpt-3.5-turbo' 表示 model 是一個字串且有預設值. -> str 表示傳回值類型為字串.
執行結果如下 :
(myvenv) D:\python\test>python news_generator_1.py
東京櫻花季即將來臨!2026年的櫻花季預計在3月底盛大開放,其中上野公園絕對是不能錯過的賞櫻勝地之一。這個充滿浪漫氛圍的公園擁有超過1000棵櫻花樹,每年都吸引著無數遊客前來欣賞這片粉紅色的花海。
除了白天的賞櫻之外,上野公園還有一項令人神往的活動,那就是傍晚的點燈活動。當夜幕降臨時,整個公園被點亮,營造出一種浪漫的氛圍,讓遊客們可以在夜幕下欣賞到迷人的夜櫻。這種別具一格的賞櫻體驗絕對讓人流連忘返。
在櫻花季期間,上野公園也會舉辦不同的活動和表演,讓遊客可以感受到濃濃的日本文化氛圍。無論是品嚐傳統的日本料理、參加傳統音樂表演還是購買精美的手工藝品,都能讓遊客們深入體驗到日本的文化魅力。
此外,上野公園周邊還擁有眾多商店和小吃攤位,供遊客選擇,讓您可以在欣賞櫻花的同時品嚐道地的日本美食和購買紀念品。不僅如此,公園周邊還有許多著名的博物館和寺廟,讓遊客可以一次過體驗到日本的豐富文化遺產。
總括而言,2024年的東京櫻花季將會是一場難忘的賞櫻之旅。無論是白天還是夜晚,在上野公園中都能感受到浪漫氛圍,讓您與摯愛共度美好時光。趕快計劃您的行程,一起來感受日本春天的魅力吧!
下面是 Gemini 版本的程式碼 :
# news_generator_2.py
from google import genai
from google.genai.errors import APIError
from dotenv import dotenv_values
config=dotenv_values('.env')
gemini_api_key=config.get('GEMINI_API_KEY')
client=genai.Client(api_key=gemini_api_key)
def ask_gemini(messages: str, model: str='gemini-2.5-flash') -> str:
try:
reply=client.models.generate_content(
model=model,
contents=messages
)
return reply.text or ''
except APIError as e:
return e.message
prompt_role='''You are an assistant for journalists.
Your task is to write articles, based on the FACTS that are given to you.
You should respect the instructions: the TONE, the LENGTH, and the STYLE'''
# 你是記者的助理.
# 你的任務是根據所提供的事實 (FACTS) 來撰寫一篇新聞稿.
# 文章需符合指定的語氣 (TONE), 長度 (LENGTH), 與風格 (STYLE).
def assist_journalist(
facts: list[str],
tone: str,
length_words: int,
style: str
) -> str:
"""根據傳入的事實、語氣, 長度與風格生成新聞稿"""
facts_str=", ".join(facts)
prompt=f'{prompt_role}\nFACTS: {facts_str}\nTONE: {tone}\nLENGTH: {length_words} words\nSTYLE: {style}'
# Gemini 可直接接受字串作為 contents, 傳入串列可能會解析失敗
return ask_gemini(prompt)
# 執行範例
if __name__ == "__main__":
result=assist_journalist(
facts=[
'2026年東京櫻花預計在3月底滿開',
'上野公園是著名的賞櫻勝地,有超過1000棵櫻花樹',
'傍晚會有點燈活動,可以欣賞浪漫的夜櫻',
'請使用繁體中文撰寫' # 提示模型使用特定語言
],
tone='浪漫且活潑',
length_words=300,
style='旅遊部落格文章'
)
print(result)
此 Gemini 版與上面 OpenAI 版主要不同處有二 :
- 錯誤處理須匯入 google.genai.errors.APIError 類別.
- Gemini SDK 可以接受字串作為 contents, 所以在 ask_gemini() 中傳入參數 messages 是字串, 而不是 OpenAI 中的串列 [{"role": "user", "content": prompt}], 否則 Gemini 的 SDK 可能會解析失敗 (視於版本相容性而定), 同時 assist_journalist() 內呼叫 ask_gemini() 也是直接傳 prompt 字串.
注意, 此處使用新版 Gemini SDK : google-genai 而非舊版的 google-generativeai, 參考下面這篇底下的補充 :
執行結果如下 :
(myvenv) D:\python\test>python news_generator_2.py
## 2026東京櫻花前線速報!上野公園千株櫻花與夢幻夜櫻等你來!
嘿,各位櫻花迷們!是不是已經開始期待下一個粉紅色的春天了呢?告訴你一個振奮人心的好消息!2026年東京的櫻花季,預計將在**3月底**達到最美、最浪漫的滿開!準備好迎接這場不容錯過的春日盛典了嗎?
想抓住這份稍縱即逝的絕美風景,怎能錯過東京最經典、最有活力的賞櫻勝地——**上野公園**呢?這裡可是名符其實的「櫻花海」!園內種植了**超過1000棵**櫻花樹,想像一下,漫步在粉白色的花海隧道下,微風輕拂,花瓣如雪般飄落,光是想像就讓人心醉神迷。白天,公園裡總是充滿著歡聲笑語,野餐、散步、拍照,每一處都是生機勃勃的春日氣息。
但別以為太陽下山就結束了!上野公園的魅力在傍晚時分才真正達到高潮!入夜後,園內精心設計的**點燈活動**會將這些嬌嫩的櫻花裝扮得如夢似幻。一盞盞溫暖的光芒,輕柔地映照著粉白花朵,將白天的活潑氣氛轉化為一片極致浪漫的**夜櫻仙境**。和心愛的人手牽手,在微光中欣賞這份獨特的景色,絕對會是2026年春日最難忘的記憶,為你的東京之旅增添無限美好的浪漫色彩!
所以,親愛的朋友們,2026年3月底,趕快把你的行事曆空下來吧!東京上野公園的千株櫻花與夢幻夜櫻正等著你,一起來感受這場浪漫又活潑的春日盛典!別再猶豫了,現在就開始規劃你的東京櫻花之旅吧!
沒有留言 :
張貼留言