mailer.txt的內容:
《貓頭鷹郵差與最後一封信》
在一座寧靜的森林裡,住著一隻年紀很大的貓頭鷹,大家都叫牠「歐里伯爺爺」。他不是一般的貓頭鷹,而是一位非常敬業的森林郵差。每天清晨,他都會準時展開翅膀,把信送到狐狸奶奶、小熊一家、刺蝟老師那裡。即使下雨或起霧,他也從不缺席。
森林裡的動物們都非常喜歡他送信時溫暖的笑容與溫柔的問候,有時信封裡還會夾一朵小花或一片秋天的紅葉。他的信不只傳遞消息,更傳遞了溫度。
但隨著年紀越來越大,歐里伯的飛行速度也慢了下來。終於有一天,他決定退休,讓年輕的白鴿小雪接手工作。
「我要送出最後一封信,再安心退休。」他拍拍翅膀,笑著對大家說。
那是一封沒有署名的信,信封是粉紅色的,上面只寫了一個名字:「小松鼠可可」。
「這孩子搬家好幾次,我得想辦法找到她,這封信不能遲到。」歐里伯想。
他飛過溪流、穿過老橡樹林、越過大霧山谷,一路打聽著小松鼠可可的下落。途中,他遇見了搬著堅果的小老鼠,摘蘋果的野兔,還有躲雨的山羊,每個人都幫他出了一點力。
終於,在一棵長滿松果的大樹下,他找到了可可。
「歐里伯爺爺!」可可開心地撲到他身上,「我以為你退休了!」
「還沒呢,這封信,是你媽媽留給你的,她半年前搬到另一片森林前託我交給你。」
可可小心地打開信,裡面寫著:
「親愛的可可,
雖然媽媽現在不在你身邊,但我一直都以你為榮。希望你每天都勇敢、快樂,記得幫助別人,因為你擁有一顆溫暖的心。
愛你的媽媽。」
讀著讀著,小松鼠的眼眶紅了。她緊緊抱著信,也抱著歐里伯。
「謝謝你,爺爺。」
那一刻,歐里伯感覺整顆心都亮了起來。他知道自己這一生最重要的事,就是把這封信送到小可可手中。
從那天起,小松鼠可可也開始幫忙做一些送信的小差事。她學著像歐里伯一樣,笑著和大家說早安,把祝福帶給每一位朋友。
森林裡的郵差換人了,但溫暖和善意,依然在森林裡飛翔著。
code:
import os
import json
from openai import OpenAI
from pathlib import Path
import time
text_file="mailer.txt"
def openai_text_to_speech(text_file=text_file, 
        output_file=f"{os.path.splitext(text_file)[0]}.mp3"):
    """
    使用 OpenAI TTS API 將文字轉換為語音
    
    優勢:
    - 最高品質的語音合成
    - 多種語音選擇
    - 支援多語言
    - 語音自然度極佳
    """
    
    try:
        # 讀取 API Key
        with open(r"D:\user\Python\GPT\json\api_key.json", "r") as f:
            api_key = json.load(f)["api_key"]
        
        # 初始化 OpenAI 客戶端
        client = OpenAI(api_key=api_key)
        
        # 讀取文字內容
        if not os.path.exists(text_file):
            # 建立故事文字檔
            story_text = """《貓頭鷹郵差與最後一封信》
在一座寧靜的森林裡,住著一隻年紀很大的貓頭鷹,大家都叫牠「歐里伯爺爺」。他不是一般的貓頭鷹,而是一位非常敬業的森林郵差。每天清晨,他都會準時展開翅膀,把信送到狐狸奶奶、小熊一家、刺蝟老師那裡。即使下雨或起霧,他也從不缺席。
森林裡的動物們都非常喜歡他送信時溫暖的笑容與溫柔的問候,有時信封裡還會夾一朵小花或一片秋天的紅葉。他的信不只傳遞消息,更傳遞了溫度。
但隨著年紀越來越大,歐里伯的飛行速度也慢了下來。終於有一天,他決定退休,讓年輕的白鴿小雪接手工作。
「我要送出最後一封信,再安心退休。」他拍拍翅膀,笑著對大家說。
那是一封沒有署名的信,信封是粉紅色的,上面只寫了一個名字:「小松鼠可可」。
「這孩子搬家好幾次,我得想辦法找到她,這封信不能遲到。」歐里伯想。
他飛過溪流、穿過老橡樹林、越過大霧山谷,一路打聽著小松鼠可可的下落。途中,他遇見了搬著堅果的小老鼠,摘蘋果的野兔,還有躲雨的山羊,每個人都幫他出了一點力。
終於,在一棵長滿松果的大樹下,他找到了可可。
「歐里伯爺爺!」可可開心地撲到他身上,「我以為你退休了!」
「還沒呢,這封信,是你媽媽留給你的,她半年前搬到另一片森林前託我交給你。」
可可小心地打開信,裡面寫著:
「親愛的可可,
雖然媽媽現在不在你身邊,但我一直都以你為榮。希望你每天都勇敢、快樂,記得幫助別人,因為你擁有一顆溫暖的心。
愛你的媽媽。」
讀著讀著,小松鼠的眼眶紅了。她緊緊抱著信,也抱著歐里伯。
「謝謝你,爺爺。」
那一刻,歐里伯感覺整顆心都亮了起來。他知道自己這一生最重要的事,就是把這封信送到小可可手中。
從那天起,小松鼠可可也開始幫忙做一些送信的小差事。她學著像歐里伯一樣,笑著和大家說早安,把祝福帶給每一位朋友。
森林裡的郵差換人了,但溫暖和善意,依然在森林裡飛翔著。"""
            
            with open(text_file, "w", encoding="utf-8") as f:
                f.write(story_text)
            print(f"✅ 已建立文字檔: {text_file}")
        
        with open(text_file, "r", encoding="utf-8") as f:
            text_content = f.read()
        
        print(f"📖 讀取檔案: {text_file}")
        print(f"📝 文字長度: {len(text_content)} 字元")
        
        # OpenAI TTS 語音選項
        voices = {
            "1": "alloy",    # 中性、平衡
            "2": "echo",     # 男性、深沉
            "3": "fable",    # 英式、優雅
            "4": "onyx",     # 男性、深沉
            "5": "nova",     # 女性、年輕
            "6": "shimmer"   # 女性、溫暖
        }
        
        print("🎤 可用語音:")
        for key, voice in voices.items():
            print(f"  {key}. {voice}")
        
        voice_choice = input("選擇語音 (1-6, 預設為 alloy): ") or "1"
        selected_voice = voices.get(voice_choice, "alloy")
        
        print(f"🎵 使用語音: {selected_voice}")
        print("🔄 正在生成語音...")
        
        start_time = time.time()
        
        # 呼叫 OpenAI TTS API
        response = client.audio.speech.create(
            model="tts-1-hd",  # 使用高品質模型 (tts-1 為標準模型)
            voice=selected_voice,
            input=text_content,
            response_format="mp3"  # 可選: mp3, opus, aac, flac
        )
        
        # 儲存音檔
        response.stream_to_file(output_file)
        
        end_time = time.time()
        process_time = end_time - start_time
        
        print(f"✅ 語音檔案已生成: {output_file}")
        print(f"⏱️  處理時間: {process_time:.2f} 秒")
        
        # 顯示檔案資訊
        file_size = os.path.getsize(output_file) / (1024 * 1024)
        print(f"📁 檔案大小: {file_size:.2f} MB")
        
        # 計算成本 (估算)
        char_count = len(text_content)
        estimated_cost = char_count * 0.000015  # $0.015 per 1K characters
        print(f"💰 預估費用: ${estimated_cost:.4f} USD")
        
        return True
        
    except Exception as e:
        print(f"❌ 生成失敗: {e}")
        return False
def test_voice_samples():
    """測試不同語音樣本"""
    test_text = "你好,這是語音測試。歡迎來到我們的 AI 工作坊。"
    
    with open(r"D:\user\Python\GPT\json\api_key.json", "r") as f:
        api_key = json.load(f)["api_key"]
    
    client = OpenAI(api_key=api_key)
    
    voices = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"]
    
    print("🎤 生成語音樣本...")
    
    for voice in voices:
        try:
            response = client.audio.speech.create(
                model="tts-1",
                voice=voice,
                input=test_text
            )
            
            sample_file = f"sample_{voice}.mp3"
            response.stream_to_file(sample_file)
            print(f"✅ {voice}: {sample_file}")
            
        except Exception as e:
            print(f"❌ {voice} 失敗: {e}")
if __name__ == "__main__":
    print("🎙️ OpenAI TTS 語音合成")
    print("=" * 50)
    
    # 詢問是否要測試語音樣本
    test_samples = input("🎵 是否先生成語音樣本?(y/n): ")
    if test_samples.lower() == 'y':
        test_voice_samples()
        print()
    
    # 生成完整故事語音
    success = openai_text_to_speech()
    
    if success:
        print("🎉 OpenAI TTS 轉換完成!")
        print(f"🎧 現在可以播放 {os.path.splitext(text_file)[0]}.mp3")code:

📖 程式碼詳解
1. 匯入套件
import os          # 檔案系統操作
import json        # JSON 檔案處理
from openai import OpenAI    # OpenAI 客戶端
from pathlib import Path     # 路徑處理
import time        # 時間計算2. 函數定義與參數
text_file="mailer.txt"  # 預設輸入檔案
def openai_text_to_speech(
    text_file=text_file, 
    output_file=f"{os.path.splitext(text_file)[0]}.mp3"
):參數說明:
- text_file: 輸入的文字檔案名稱
- output_file: 輸出的 MP3 檔案名稱(自動從文字檔名生成)
3. API Key 讀取
# 讀取 API Key
with open(r"D:\user\Python\GPT\json\api_key.json", "r") as f:
    api_key = json.load(f)["api_key"]
# 初始化 OpenAI 客戶端
client = OpenAI(api_key=api_key)重要提醒:
- 請修改路徑為你的實際 API Key 檔案路徑
- 確保檔案格式為 UTF-8 編碼
4. 文字檔案處理
# 檢查檔案是否存在
if not os.path.exists(text_file):
    # 如果不存在,建立預設故事文字檔
    story_text = """故事內容..."""
    
    with open(text_file, "w", encoding="utf-8") as f:
        f.write(story_text)
    print(f"✅ 已建立文字檔: {text_file}")
# 讀取文字內容
with open(text_file, "r", encoding="utf-8") as f:
    text_content = f.read()編碼重點:
- 使用 encoding="utf-8"確保中文字元正確處理
- 自動建立預設文字檔案,方便測試
5. 語音選擇系統
# OpenAI TTS 語音選項
voices = {
    "1": "alloy",    # 中性、平衡
    "2": "echo",     # 男性、深沉
    "3": "fable",    # 英式、優雅
    "4": "onyx",     # 男性、深沉
    "5": "nova",     # 女性、年輕
    "6": "shimmer"   # 女性、溫暖
}
# 使用者選擇
voice_choice = input("選擇語音 (1-6, 預設為 alloy): ") or "1"
selected_voice = voices.get(voice_choice, "alloy")voice_choice = input(“選擇語音 (1-6, 預設為 alloy): “) or “1”
🧠 運作邏輯
- input()執行 → 使用者輸入或按 Enter(獲得空字串,視為False)
- 真值判斷 → Python 檢查輸入值是否為「真」
- or運算 → 如果左邊為「假」,返回右邊的值(短路邏輯)
語音特色:
- alloy:平衡且通用的中性聲音,適合多元用途。
- echo:溫暖且低沉的男性聲音,適合正式、穩重的內容。
- fable:英國腔調,溫和且富有敘事感,適合講故事或需要英式口音的場合。
- onyx:堅定且深沉的男性聲音,帶有權威感,適合正式或專業內容。
- nova:明亮且親切的年輕女性聲音,適合輕鬆活潑的內容。
- shimmer:溫柔且溫暖的女性聲音,適合溫馨、故事朗讀等情境。
參考: openAI Platform
6. OpenAI TTS API 調用
# 計時開始
start_time = time.time()
# 呼叫 OpenAI TTS API
response = client.audio.speech.create(
    model="tts-1-hd",        # 高品質模型
    voice=selected_voice,    # 選擇的語音
    input=text_content,      # 輸入文字
    response_format="mp3"    # 輸出格式
)
"""
#標準模式(一次全部):
response = client.audio.speech.create(
    model="gpt-4o-mini-tts",
    voice="coral",
    input="Today is a wonderful day to build something people love!",
    instructions="Speak in a cheerful and positive tone.",
)
with open("speech.mp3", "wb") as f:
    f.write(response.content)
    
#串流模式(邊產生、邊存檔):
with client.audio.speech.with_streaming_response.create(
    model="gpt-4o-mini-tts",
    voice="coral",
    input="Today is a wonderful day to build something people love!",
    instructions="Speak in a cheerful and positive tone.",
) as response:
    response.stream_to_file(speech_file_path)
"""
# 儲存音檔
response.stream_to_file(output_file)
# 計時結束
end_time = time.time()模型選擇:
- tts-1: 標準模型,較快且便宜
- tts-1-hd: 高品質模型,音質更佳但較貴
openAI Platform: 
One of the available TTS models: tts-1, tts-1-hd or gpt-4o-mini-tts.
輸出格式選項:
- mp3: 最常用,檔案小
- opus: 適合即時應用
- aac: Apple 生態系統
- flac: 無損音質質
- 7. 結果報告
# 處理時間
process_time = end_time - start_time
print(f"⏱️  處理時間: {process_time:.2f} 秒")
# 檔案大小
file_size = os.path.getsize(output_file) / (1024 * 1024)
print(f"📁 檔案大小: {file_size:.2f} MB")
# 費用估算
char_count = len(text_content)
estimated_cost = char_count * 0.000015  # $0.015 per 1K characters
print(f"💰 預估費用: ${estimated_cost:.4f} USD")輸出的mp3檔:

推薦hahow線上學習python: https://igrape.net/30afN
Google Text-to-Speech (gTTS)
簡介
- 一款基於 Google Translate 的開源 Python 庫,支持多語言文字轉語音。
- 非常輕量、易用,適合快速生成語音文件。
特點
- 支持語言:100+ 種語言,包括中文。
- 免費:僅需網路連線即可使用。
- 輸出格式:生成 .mp3文件。
安裝
pip install gtts使用範例
from gtts import gTTS
text = "你好,歡迎使用文字轉語音工具!"
tts = gTTS(text, lang='zh')
tts.save("output.mp3")優勢
- 簡單易用,快速生成語音文件。
- 無需本地計算資源,適合低性能設備。
限制
- 需要穩定的網路連線。
- 語音自然度稍低,適合基礎 TTS 需求。
推薦hahow線上學習python: https://igrape.net/30afN
Edge-TTS(推薦)
- Microsoft Edge 瀏覽器的 TTS
- Python 套件:edge-tts
- 音質優秀,完全免費
- 支援 SSML 標記 (Speech Synthesis Markup Language)
# 安裝:pip install edge-tts
import edge_tts
import asyncio
"""
asyncio 其實是 async + io 的組合詞:
async:非同步(asynchronous)
io:輸入/輸出(input/output)
"""
async def main():
    text = "你好,這是測試"
    voice = "zh-TW-HsiaoChenNeural"
    
    communicate = edge_tts.Communicate(text, voice)
    await communicate.save("output.mp3")
    #return True  # 有需要的話可以加
asyncio.run(main())
"""
result = asyncio.run(main())
print(result)  # 若 main 有 return True,這裡會印出 True
"""程式碼詳細解釋:
1. 安裝套件
# 安裝:pip install edge-tts- 這是在終端機/命令提示字元中執行的指令
- 安裝 Microsoft Edge 瀏覽器的 TTS 引擎 Python 套件
2. 導入必要模組
import edge_tts    # Edge TTS 主要功能
import asyncio     # Python 的非同步程式設計模組3. 非同步函數定義
async def main():- async def定義一個非同步函數
- 非同步函數可以使用 await關鍵字
- 必須在特殊環境(event loop)中執行
4. 設定參數
text = "你好,這是測試"                # 要轉換的文字
voice = "zh-TW-HsiaoChenNeural"      # 語音角色(台灣女聲)
"""
女聲:zh-TW-HsiaoYuNeural #小雨
男聲:zh-TW-YunJheNeural  #雲傑
"""5. 建立通訊物件
communicate = edge_tts.Communicate(text, voice)
"""
tts = edge_tts.Communicate(
    text="語速和語調調整範例。",
    voice="zh-TW-HsiaoYuNeural",
    rate="+20%",
    pitch="+5Hz"
)
#調整語速:rate="+10%" 或 rate="-10%"
#調整語調:pitch="+5Hz" 等
"""- 創建一個 Communicate 物件
- 負責與 Edge TTS 服務通訊
Microsoft TTS 聲音清單:zh-TW-HsiaoChenNeural (女性)zh-TW-YunJheNeural (男性)zh-TW-HsiaoYuNeural (女性)
6. 儲存音檔
await communicate.save("output.mp3")- await等待非同步操作完成
- 將語音儲存為 output.mp3
7. 執行主程式
asyncio.run(main())- 創建新的 event loop 並執行 main()
- 這裡是問題所在!
為什麼會出錯?
Event Loop 概念圖解:
正常 Python 環境:
┌─────────────────┐
│ Python Script   │
│                 │
│ asyncio.run() ──┼──> 創建新 Event Loop ✓
│                 │
└─────────────────┘
Jupyter/IPython 環境:
┌─────────────────────┐
│ Jupyter Notebook    │
│                     │
│ 已有 Event Loop 運行 │ <── 這裡已經有了!
│                     │
│ asyncio.run() ──────┼──> 試圖創建新 Loop ✗ (錯誤!)
│                     │
└─────────────────────┘什麼是 Event Loop?
想像一個餐廳:
- 同步程式 = 一個服務生,一次只服務一桌
- 非同步程式 = 一個服務生,同時處理多桌
- Event Loop = 服務生的工作流程管理系統
# 同步方式(傳統)
def 點餐():
    顧客A點餐()  # 等 A 點完
    顧客B點餐()  # 再等 B 點完
    顧客C點餐()  # 最後等 C
# 非同步方式(edge-tts 使用)
async def 點餐():
    await 顧客A點餐()  # A 在想的時候
    await 顧客B點餐()  # 可以先問 B
    await 顧客C點餐()  # 也可以處理 C正確的使用方式:
選項 1:純 Python 腳本(原始寫法正確)
# script.py
import edge_tts
import asyncio
async def main():
    text = "你好,這是測試"
    voice = "zh-TW-HsiaoChenNeural"
    
    communicate = edge_tts.Communicate(text, voice)
    await communicate.save("output.mp3")
    print("語音檔案已生成:output.mp3")
# 在終端機執行:python script.py
if __name__ == "__main__":
    asyncio.run(main())  # ✓ 這裡正確!選項 2:Jupyter Notebook 中使用
# 在 Jupyter cell 中
import edge_tts
text = "你好,這是測試"
voice = "zh-TW-HsiaoChenNeural"
communicate = edge_tts.Communicate(text, voice)
await communicate.save("output.mp3")  # 直接 await,不用 asyncio.run()選項 3:通用解決方案
import edge_tts
import asyncio
import nest_asyncio
# 允許巢狀 event loop
nest_asyncio.apply()
async def text_to_speech(text, filename="output.mp3"):
    """
    將文字轉換為語音檔案
    
    參數:
        text: 要轉換的文字
        filename: 輸出檔案名稱
    """
    voice = "zh-TW-HsiaoChenNeural"
    
    print(f"正在生成語音:{text[:20]}...")
    communicate = edge_tts.Communicate(text, voice)
    await communicate.save(filename)
    print(f"完成!檔案儲存為:{filename}")
# 這樣在任何環境都能用
asyncio.run(text_to_speech("歡迎使用語音合成系統"))簡單類比解釋:
同步 vs 非同步
同步(傳統方式):
下載檔案A (等3秒) ━━━━━━━━━━
下載檔案B (等2秒)          ━━━━━━
下載檔案C (等1秒)                ━━
總時間:6秒非同步(edge-tts方式):
下載檔案A ━━━━━━━━━━
下載檔案B ━━━━━━
下載檔案C ━━
總時間:3秒(同時進行)完整實用範例:
# tts_helper.py
import edge_tts
import asyncio
import os
class SimpleTTS:
    """簡單的 TTS 工具類"""
    
    def __init__(self):
        # 設定預設語音
        self.default_voice = "zh-TW-HsiaoChenNeural"
        
    def create_speech(self, text, output_file="speech.mp3", voice=None):
        """
        同步方法:生成語音檔案
        """
        async def _async_create():
            voice_to_use = voice or self.default_voice
            communicate = edge_tts.Communicate(text, voice_to_use)
            await communicate.save(output_file)
        
        # 智慧判斷如何執行
        try:
            # 嘗試取得現有的 event loop
            loop = asyncio.get_running_loop()
            # 如果成功,表示在 Jupyter 等環境
            import nest_asyncio
            nest_asyncio.apply()
            loop.run_until_complete(_async_create())
        except RuntimeError:
            # 如果失敗,表示在一般 Python 環境
            asyncio.run(_async_create())
        
        print(f"✅ 語音已儲存至:{output_file}")
        return output_file
# 使用方式
tts = SimpleTTS()
tts.create_speech("這是一個測試")
tts.create_speech("Hello World", "english.mp3", "en-US-AriaNeural")重點整理:
- edge-tts 使用非同步設計是為了效能(可同時處理多個請求)
- asyncio.run() 會創建新的 event loop
- Jupyter 已有 event loop,所以不能再創建
- 解決方式:
- 純 Python:直接用原始寫法
- Jupyter:用 await 不用 asyncio.run()
- 通用:用 nest_asyncio
 
推薦hahow線上學習python: https://igrape.net/30afN











![Python: list.index() 只能找到第一個元素的index,若元素有重複,如何找出所有index? indexes = [index for index, value in enumerate(my_list) if value == target] Python: list.index() 只能找到第一個元素的index,若元素有重複,如何找出所有index? indexes = [index for index, value in enumerate(my_list) if value == target]](https://i1.wp.com/savingking.com.tw/wp-content/uploads/2024/10/20241010101216_0_12b6c0.png?quality=90&zoom=2&ssl=1&resize=350%2C233)
 
																			 
																			![Python: 如何用 pandas.DataFrame.apply 讓DataFrame增加新的一欄 ; df[“mean”] = df.apply( np.mean, axis=1) ; DataFrame.apply(func, axis=0, raw=False, result_type=None, args=(), **kwargs) - 儲蓄保險王](https://savingking.com.tw/wp-content/uploads/2023/05/20230519084320_22-520x245.png) 
																			
近期留言