<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>YouTube｜林鼎淵 Dean Lin</title>
    <link>https://deanlin.net/tags/youtube/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>YouTube｜林鼎淵 Dean Lin</title><link>https://deanlin.net/tags/youtube/</link><width>144</width><height>144</height></image>
    <description>林鼎淵（Dean Lin）的部落格：生成式 AI 企業內訓講師、外商資安公司軟體專家、7 本書作者。400 多篇文章用白話分享生成式 AI 實戰、Claude Code 與 Vibe Coding 教學、團隊合作與職場成長。</description>
    <generator>Hugo</generator>
    <language>zh-tw</language>
    <copyright>© 2020–2026 林鼎淵 Dean Lin</copyright>
    <lastBuildDate>Wed, 20 May 2026 12:16:31 +0800</lastBuildDate>
    <atom:link href="https://deanlin.net/tags/youtube/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>人生不一定只能活成一種樣子</title>
      <link>https://deanlin.net/blog/202605/more-than-one-way-to-live/</link>
      <pubDate>Wed, 20 May 2026 12:16:31 +0800</pubDate>
      <guid>https://deanlin.net/blog/202605/more-than-one-way-to-live/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>某次聚會時，有位朋友跟我說了一句話，讓我記到現在。他說：</description>
      <media:content url="https://deanlin.net/blog/202605/more-than-one-way-to-live/images/more-than-one-way-to-live-og_hu_6c249a0770aa7f01.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<p><img src="https://deanlin.net/blog/202605/more-than-one-way-to-live/images/more-than-one-way-to-live-01.webp" width="1400" height="814" alt="人生不一定只能活成一種樣子（圖 1）" fetchpriority="high" decoding="async"></p>
<p>某次聚會時，有位朋友跟我說了一句話，讓我記到現在。他說：</p>
<blockquote class="pullquote"><p>如果人生是一場終究會走向終點的旅程，那你是我周圍朋友中最賺的！</p>
</blockquote>
<blockquote class="pullquote"><p>因為你在不同領域，都努力活出了自己的樣子。</p>
</blockquote>
<p>其實聽到當下有點不好意思。因為我很清楚，這一路並不是每個選擇都很篤定。</p>
<p>更多時候，我只是帶著對未知的好奇，還有想把事情做好的信念，慢慢走到了今天。</p>
<ul>
<li>在本職工作方面，我做過工程師、專案經理、技術主管，目前在外商擔任 Software Specialist。</li>
<li>在魔術領域，我是花式撲克高手，曾三度站上公演舞台，也發表過國際魔術道具。</li>
<li>在作家領域，我出版過 7 本書，主題橫跨網路爬蟲、工程師職涯、AI 工具應用等多個領域，並連續多年入選百大暢銷書。</li>
<li>在講師領域，我累積超過 100 場授課經驗，曾受邀到政府機構、500 大企業與學校團體授課，分享 AI、職涯與實務應用。</li>
</ul>
<p>而經營 YouTube 對我來說，是一段全新的旅程。</p>
<p>一開始只是想把自己學過的東西、踩過的坑、整理過的方法記錄下來。</p>
<p>後來在留言區發現，<strong>原來那些我曾經卡關的地方，也是別人正在煩惱的問題。</strong></p>
<p>所以不管我分享的是自我成長、職涯發展，還是 AI 應用，背後其實都來自同一個很單純的想法：</p>
<blockquote>
<p>「如果這些經驗曾經幫助過我，那它也可能在某個時刻，剛好幫上別人的忙。」</p>
</blockquote>
<p>人生有些選擇看起來像繞遠路。</p>
<p>但回頭看，那些路都成為生命裡很重要的養分。</p>
<p>謝謝每一位曾經支持我、鼓勵我、留言給我，與默默看完影片的朋友。</p>
<p>你們讓我知道，這些分享不是自言自語，而是真的有機會陪某些人走過一小段路。</p>
<p>如果你想聽我分享哪一段故事，歡迎留言～</p>
<p>也許下一篇，我就從那個故事開始說起。</p>
<hr>
<p>如果對自我成長、職涯發展、AI 技術等主題有興趣，歡迎訂閱我的頻道喔～</p>
<p><a href="https://www.youtube.com/@dlcorner?fbclid=IwZXh0bgNhZW0CMTAAYnJpZBExMkdPdDZaNTVteVlKZTlWNXNydGMGYXBwX2lkEDIyMjAzOTE3ODgyMDA4OTIAAR6_fAdiFTwEX8xCU5f6zTVAQ6FsZNtnxzAGF5N8JzKGp2hydhg_IdJfIjwt6g_aem_NPHLndLQQfq773PNiS4Wzg">https://www.youtube.com/@dlcorner</a></p>
<figure class="figure"><img src="https://deanlin.net/blog/202605/more-than-one-way-to-live/images/more-than-one-way-to-live-02.webp" width="1400" height="914" alt="林鼎淵著作《工程師下班有約：企業內訓講師帶你認清職涯真相！》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.tenlong.com.tw/products/9786264142083">https://www.tenlong.com.tw/products/9786264142083</a></figcaption>
</figure>

]]></content:encoded>
    </item>
    <item>
      <title>如果失敗與挫折才是常態，你還有繼續挑戰的勇氣嗎？</title>
      <link>https://deanlin.net/blog/202512/courage-to-keep-trying/</link>
      <pubDate>Sat, 27 Dec 2025 20:44:55 +0800</pubDate>
      <guid>https://deanlin.net/blog/202512/courage-to-keep-trying/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>在訂閱破萬這天，我想分享一個讓我開始經營 YouTube 的動機；不是熱血、無關夢想，而是差點社死的經驗 😳</description>
      <media:content url="https://deanlin.net/blog/202512/courage-to-keep-trying/images/courage-to-keep-trying-og_hu_b4e9e16831a2cc09.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<p>在<a href="https://www.youtube.com/@dlcorner">訂閱破萬這天</a>，我想分享一個讓我開始<a href="https://www.youtube.com/@dlcorner">經營 YouTube 的動機</a>；不是熱血、無關夢想，而是差點社死的經驗 😳</p>
<p><img src="https://deanlin.net/blog/202512/courage-to-keep-trying/images/courage-to-keep-trying-01.webp" width="1400" height="1096" alt="如果失敗與挫折才是常態，你還有繼續挑戰的勇氣嗎？（圖 1）" fetchpriority="high" decoding="async"></p>
<p>年初某個假日，我受邀擔任全國教師線上研習的講師。</p>
<p>課程前一晚，我照慣例跑了一遍流程，確認網路、聲音、畫面，全都沒問題。</p>
<p>但課程當天，我準備開始講課時，意外發生了：</p>
<blockquote class="pullquote"><p>Google Meet 突然無法分享電腦螢幕 😱</p>
</blockquote>
<p>更慘的是，那場研習安排的是實戰演練；如果看不到操作畫面，學員只能靠想像力上課。</p>
<p>我和主持人嘗試了各種方式，卻始終無法解決；而線上，還有 600 多人在等待。</p>
<p>時間，就這樣一分一秒流逝 ⏳</p>
<p>聊天室裡有人提議：「不然改用 YouTube 直播？」</p>
<p>我立刻嘗試，卻崩潰的發現直播無法順利開始 😫</p>
<p>查了一下才知道：</p>
<blockquote>
<p>YouTube 直播需要訂閱數超過 50 人，才可以開直播給最多 75 位觀眾</p>
<p>訂閱數要超過 1000 人，才沒有觀眾人數限制</p>
<p>而我當時只有 30 多個訂閱…</p>
</blockquote>
<p>最後，是先靠主持人用平板分享畫面，才撐過前半場（只有平板可以分享），直到後半段 Google Meet 恢復正常，才勉強完成課程。</p>
<p>分享這則故事，是想要告訴大家：「不管準備的多完善，都可能被一個意外打亂」</p>
<p>所謂的專業，並不是從不失誤；而是能把遇過的「意外」納入流程。</p>
<p>所以我開始反問自己：「如果下一次再出狀況，我的備案是什麼？」</p>
<p>除了購買 Zoom、Teams 等會議軟體外，我也把 YouTube 直播算進一個備案。</p>
<p>在我發布 10 隻長影片、10 隻短影片後，終於在 10/24，<a href="https://www.youtube.com/@dlcorner">YouTube 訂閱</a>突破 1000 人。</p>
<p>將這個開直播的備案做起來了！</p>
<p>這個月，我講了 5 場線上研習；跟年初不同的是，現在我有更多面對意外的底氣 💪</p>
<p>儘管意外發生當下，挫折感很重；但現在回頭看，這些經歷都在累積我的能量。</p>
<hr>
<p>我覺得失敗經驗，遠比成功的故事更值得被分享；因為成功難以複製，但失敗幾乎人人都會遇到。</p>
<p>如果對自我成長、職涯發展、AI 技術等主題有興趣，歡迎訂閱我的頻道喔～</p>
<p><a href="https://www.youtube.com/@dlcorner?fbclid=IwZXh0bgNhZW0CMTAAYnJpZBExMkdPdDZaNTVteVlKZTlWNXNydGMGYXBwX2lkEDIyMjAzOTE3ODgyMDA4OTIAAR6_fAdiFTwEX8xCU5f6zTVAQ6FsZNtnxzAGF5N8JzKGp2hydhg_IdJfIjwt6g_aem_NPHLndLQQfq773PNiS4Wzg">https://www.youtube.com/@dlcorner</a></p>
<figure class="figure"><img src="https://deanlin.net/blog/202512/courage-to-keep-trying/images/courage-to-keep-trying-02.webp" width="1400" height="914" alt="林鼎淵著作《工程師下班有約：企業內訓講師帶你認清職涯真相！》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.tenlong.com.tw/products/9786264142083">https://www.tenlong.com.tw/products/9786264142083</a></figcaption>
</figure>

]]></content:encoded>
    </item>
    <item>
      <title>沒有意志力？那是因為缺少環境的約束</title>
      <link>https://deanlin.net/blog/202509/afteroffice1-soldier-life/</link>
      <pubDate>Tue, 02 Sep 2025 21:07:47 +0800</pubDate>
      <guid>https://deanlin.net/blog/202509/afteroffice1-soldier-life/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>無論學校還是社會，只要你想，隨時都能離開；不過一旦踏入軍營，這就不是你可以說來就來，說走就走的地方了。我在過去 10 年的工作中，遇過各種奇葩的主管、同事、客戶，也在高壓不合理的環境待過好幾年。但到目前為止，我認為工作再苦，都遠遠不及當兵的苦。</description>
      <media:content url="https://deanlin.net/images/post/202509/afteroffice1-soldier-life/cover_hu_6497b41a20b067b8.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<div class="yt" data-yt="pmAKeqSjOtY" data-title="【工程師下班有約 EP05】人的極限，是由環境定義的 #軍人節 #總統府 #當兵 #退伍 #壓力">
  <a class="yt-link" href="https://www.youtube.com/watch?v=pmAKeqSjOtY" target="_blank" rel="noopener" aria-label="播放影片：【工程師下班有約 EP05】人的極限，是由環境定義的 #軍人節 #總統府 #當兵 #退伍 #壓力">
    <img src="https://i.ytimg.com/vi/pmAKeqSjOtY/hqdefault.jpg" alt="" width="480" height="360" loading="lazy" decoding="async">
    <span class="yt-play" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 5.2v13.6L19 12z"/></svg></span>
    <span class="yt-title">【工程師下班有約 EP05】人的極限，是由環境定義的 #軍人節 #總統府 #當兵 #退伍 #壓力</span>
  </a>
</div>

<blockquote>
<p>人的極限，是根據環境來定義的</p>
</blockquote>
<p>無論學校還是社會，只要你想，隨時都能離開；不過一旦踏入軍營，這就不是你可以說來就來，說走就走的地方了。</p>
<p>我在過去 10 年的工作中，遇過各種奇葩的主管、同事、客戶，也在高壓不合理的環境待過好幾年。</p>
<p>但到目前為止，<strong>我認為工作再苦，都遠遠不及當兵的苦。</strong></p>
<h2 id="-不要為了蠅頭小利讓自己承擔多餘的風險">不要為了蠅頭小利，讓自己承擔多餘的風險<a class="h-anchor" href="#-%e4%b8%8d%e8%a6%81%e7%82%ba%e4%ba%86%e8%a0%85%e9%a0%ad%e5%b0%8f%e5%88%a9%e8%ae%93%e8%87%aa%e5%b7%b1%e6%89%bf%e6%93%94%e5%a4%9a%e9%a4%98%e7%9a%84%e9%a2%a8%e9%9a%aa" aria-label="這個段落的連結"></a></h2>
<hr>
<p>其實我原本可以當爽兵，因為在新訓的時候，就已經被憲兵指揮部選去當資訊兵。</p>
<p>但人生總是有個 But，在憲訓的時候，有次長官集合部隊，問大家想不想考士官當班長；但當時台下根本沒幾個人有意願，於是長官拋出誘餌：「<strong>只要報名考士官，不管有沒有考上，都會讓你放么八假！</strong>」</p>
<p>因為當時軍中無法使用智慧型手機、伙食不合胃口、對外通訊還要靠電話卡。</p>
<p>在這個與現實世界隔離的環境中，<strong>哪怕是一分鐘，大家都想早點離開。</strong></p>
<p>因此么八假這個誘餌，成功讓現場超過 1/3 的人舉手報名，而我也是其中一人。</p>
<p>到了考試現場後，我從頭到尾都用猜的。大概只花 5 分鐘就交卷了，交卷後我心想：「全部都亂寫，總不可能考上吧？」</p>
<p>但人生總在你沒防備的時候給你一記重拳，<strong>我一向很差的考運，好死不死的在這個時候大爆發。</strong></p>
<p>印象滿分是 180 分，只要超過 100 分就會錄取，<strong>結果我的成績在印出來的時候，上面寫著「101 分」。</strong></p>
<blockquote>
<p>那時，我瞭解了什麼叫做命中注定，還有⋯不做死就不會死。</p>
</blockquote>
<h2 id="-有些經歷可以講一輩子但你不會想體驗第二次">有些經歷可以講一輩子，但你不會想體驗第二次<a class="h-anchor" href="#-%e6%9c%89%e4%ba%9b%e7%b6%93%e6%ad%b7%e5%8f%af%e4%bb%a5%e8%ac%9b%e4%b8%80%e8%bc%a9%e5%ad%90%e4%bd%86%e4%bd%a0%e4%b8%8d%e6%9c%83%e6%83%b3%e9%ab%94%e9%a9%97%e7%ac%ac%e4%ba%8c%e6%ac%a1" aria-label="這個段落的連結"></a></h2>
<hr>
<p>其實當士官也沒什麼，就是比一般兵忙一點而已。</p>
<p>直到某天，有位總統府的長官來到營區，跟大家宣傳進總統府有哪些好處，他是這麼說的：</p>
<ol>
<li><strong>保證待在台北</strong>，因為當年義務役士官一個月薪水才一萬二，如果離居住地太遠，光車錢就吃不消。</li>
<li><strong>一天只要 3 班哨</strong>，空閒時間可以自由運用。</li>
<li><strong>營區內可以(有限制的)使用智慧型手機</strong>，這在當年是相當大的誘因，因為其他營區只能使用 nokia3310 這類智障型手機。</li>
<li><strong>伙食超級好吃</strong>，因為來的長官白白胖胖，很像七龍珠的普烏，所以很有說服力</li>
</ol>
<p>最後他說，當兵只有一次，<strong>為何不挑戰「天下第一營」的最高榮譽呢？</strong></p>
<p>聽完宣傳後，可能當下腦袋不太靈光，我竟然主動報名；不要以為只有我的腦波弱，當時同期有 60% 的人報名，可見來的長官多會宣傳。</p>
<p>不過等報名表交出去後，我們才發現<strong>自己忘記總統府是憲兵裡面最硬的單位，就是因為沒人想去，所以才要派人來宣傳啊！</strong></p>
<p>不過總統府只錄取兩個人，當我在祈禱自己不會被挑到的時候，輔導長召集大家到會議室公布錄取名單，後面的故事大家也知道了。</p>
<p><strong>我就是那個被國家最高行政機關選中的男人！</strong></p>
<blockquote>
<p>不過分享總統府的故事前，先聲明一下，接下來的內容僅為 10 年前服役的個人經驗，不包含任何機敏資訊。</p>
</blockquote>
<h2 id="-意志力的上限是由環境所決定的">意志力的上限，是由環境所決定的<a class="h-anchor" href="#-%e6%84%8f%e5%bf%97%e5%8a%9b%e7%9a%84%e4%b8%8a%e9%99%90%e6%98%af%e7%94%b1%e7%92%b0%e5%a2%83%e6%89%80%e6%b1%ba%e5%ae%9a%e7%9a%84" aria-label="這個段落的連結"></a></h2>
<hr>
<p>進總統府後，我只要一放假就會連續睡 12 小時以上。</p>
<p>進去前，我只知道這個單位很硬，但進去後，我才發現他對每一個面向都近乎苛求。</p>
<p>因為總統府是國家的門面，所以服裝儀容是用最高標準檢核的。當年武裝哨都要穿著甲服，無論春夏秋冬都是長褲長袖長靴鋼盔。</p>
<p><img src="https://deanlin.net/images/post/202509/afteroffice1-soldier-life/task_hu_dcd9f57dd15876fa.webp" width="1184" height="712" alt="元旦任務時，總統府正門前站哨的兩名憲兵" fetchpriority="high" decoding="async"></p>
<p>所謂的甲服，就是對服儀要求近乎完美，<strong>上哨前衣服褲子都要用熨斗燙線，不能有皺摺；而且長靴要擦到能當鏡子</strong>。</p>
<blockquote>
<p>我說的不是誇飾，而是基本要求。</p>
</blockquote>
<p>另外在上哨前除了要檢查服儀外，還要考當日情資；到了哨點後，你更要繃緊神經！</p>
<p>畢竟總統府位於市中心，周圍除了有路過的一般民眾外，五院八部的長官與高階將領也時常經過。</p>
<p><strong>如果站哨時三七步、彎腰駝背被長官看到，下哨就準備倒大霉了。</strong></p>
<p>而且在最高行政機關當兵，你的記憶力要不錯；除了要記得重要的長官外，一些被列管的特殊人士你更是要牢牢記住。</p>
<p><strong>長官認不出來，頂多被電、寫悔過書；但如果你沒注意到特殊人士靠近，那真的會有危險。</strong></p>
<p>因為有時會有精神異常、或是對政府不滿的民眾路過，要是打瞌睡，真的會出事！</p>
<p>這邊放上兩個新聞案例，<strong>一個是砂石車衝撞總統府，另一個是憲兵被武士刀砍</strong>：</p>
<p><img src="https://deanlin.net/images/post/202509/afteroffice1-soldier-life/car-crash_hu_af65584d69a84961.webp" width="1024" height="683" alt="砂石車衝撞總統府正門後的新聞照片" loading="lazy" decoding="async">
<img src="https://deanlin.net/images/post/202509/afteroffice1-soldier-life/nife_hu_f6c624c3bd385bec.webp" width="847" height="668" alt="總統府憲兵遭武士刀砍傷新聞，警方架走嫌犯" loading="lazy" decoding="async"></p>
<p>說了這麼多，就是想表達在總統府站的每班哨都要承受極大壓力；而且更可怕的是，<strong>在這裡當兵，幾乎每天都要輪夜哨。</strong></p>
<p>因為勤務非常繁重，連上弟兄都會戲稱自己是「狂站士」！</p>
<p>進總統府前，我覺得自己的抗壓性挺不錯的；但進去後我才發現，原來，<strong>自己的抗壓性還有這麼大的成長空間</strong>。</p>
<p>出社會這麼多年，每當工作遇到困難，或是不合理的對待時。我就會回想當年的軍旅生涯，想著想著，就覺得眼前的問題不是問題。</p>
<h2 id="-環境會逼出一個人的潛力">環境會逼出一個人的潛力<a class="h-anchor" href="#-%e7%92%b0%e5%a2%83%e6%9c%83%e9%80%bc%e5%87%ba%e4%b8%80%e5%80%8b%e4%ba%ba%e7%9a%84%e6%bd%9b%e5%8a%9b" aria-label="這個段落的連結"></a></h2>
<hr>
<p>這篇文章並不是鼓勵大家挑最難的路走，只是想讓大家知道：「所謂的『極限』很多時候都是自己想像出來的！」</p>
<p>當環境變成不可抗力後，人的求生本能會盡可能讓你去適應它；但是也請量力而為，<strong>因為當年勤務過度繁重，導致我當兵後期頻繁進出醫院</strong>。</p>
<p>甚至退伍多年後，腳在換季時還是經常出狀況，嚴重的時候連走路都有困難。</p>
<p>儘管這些故事回憶起來很有成就感，但後遺症讓我在舊傷發作時，要靠吃止痛藥才能撐下去。</p>
<p><strong>記住，痛苦會習慣，但不會減輕。</strong></p>
<h2 id="-當兵是橫跨世代的共同回憶">當兵，是橫跨世代的共同回憶<a class="h-anchor" href="#-%e7%95%b6%e5%85%b5%e6%98%af%e6%a9%ab%e8%b7%a8%e4%b8%96%e4%bb%a3%e7%9a%84%e5%85%b1%e5%90%8c%e5%9b%9e%e6%86%b6" aria-label="這個段落的連結"></a></h2>
<hr>
<p><img src="https://deanlin.net/images/post/202509/afteroffice1-soldier-life/cover_hu_1349b1be88233dea.webp" width="1440" height="810" alt="退伍日的憲兵禮服照：在天下第一營當兵是我一輩子的榮耀" loading="lazy" decoding="async"></p>
<p>當過兵的男生，只要聊到當兵的話題就有說不完的故事。就算第一次見面，也能像老朋友一樣聊的很興奮。</p>
<p>因為對大多數的男生來說，<strong>當兵是一種強制「脫離舒適圈」的體驗</strong>，而軍營裡經歷的事情，對剛從校園畢業的學生絕對稱得上「震撼教育」。</p>
<p>而且越苦的日子記憶越深刻，即使退伍多年依然記憶猶新。</p>
<p>就像美國名將麥克阿瑟，曾說過一句讓退伍的人很有共鳴的話。</p>
<p>他說：「<strong>給我一百萬，要換取我的入伍回憶，我不願意；但給我一百萬，要我重新入伍，我更不願意！</strong>」</p>
<p>我的軍旅故事就分享到這邊，最後感謝平日盡忠職守的軍人們，謝謝你們的付出。</p>
<p>如果我的故事讓你感到共鳴，歡迎大家留言分享自己的軍旅生活～</p>
<blockquote>
<p>環境會逼出潛力，求生本能會讓你適應，但習慣痛苦，不代表痛苦不存在</p>
</blockquote>
<hr>
<p>我是鼎淵，一個熱愛分享 AI 知識、自我成長、職涯發展主題的工程師。</p>
<p>歡迎追蹤<a href="https://www.youtube.com/@dlcorner">我的 YouTube</a>，帶你掌握時代趨勢！</p>
<blockquote>
<p>《工程師下班有約》網路書店： 🐲<a href="https://www.tenlong.com.tw/products/9786264142083">天瓏書局</a></p>
</blockquote>
<hr>
<blockquote>
<p>我是林鼎淵，如果覺得這邊文章對你有幫助，歡迎追蹤筆者的 <a href="https://www.facebook.com/deanlinbao">Facebook</a> 與 <a href="https://www.youtube.com/@dlcorner">YouTube</a>，我會持續分享實用的新知識 💡</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>沒有白走的路！如何找到自己的天賦</title>
      <link>https://deanlin.net/blog/202508/afteroffice2-hard-work-talent-or-timing/</link>
      <pubDate>Wed, 13 Aug 2025 22:07:47 +0800</pubDate>
      <guid>https://deanlin.net/blog/202508/afteroffice2-hard-work-talent-or-timing/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>如果用盡全力還是看不到成果，就代表自己沒有天賦嗎？大一到大三，我參 加了 23 場比賽，但一場都沒贏過，甚至連個參加獎都沒有，血淋淋的現實告訴我：「你不過如此。」但我沒有選擇放棄，而是持續尋找新的可能性；最終在大四那年，我找到適合自己的路！有時你不是沒有天賦，只是嘗試的領域不夠多；或者跟我一樣，複合領域領域才是我們大顯身手的地方！</description>
      <media:content url="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/cover_hu_93689ddd96baa7a9.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<div class="yt" data-yt="qtWbQh7wQSs" data-title="【工程師下班有約 EP04】沒有白走的路！如何找到自己的天賦">
  <a class="yt-link" href="https://www.youtube.com/watch?v=qtWbQh7wQSs" target="_blank" rel="noopener" aria-label="播放影片：【工程師下班有約 EP04】沒有白走的路！如何找到自己的天賦">
    <img src="https://i.ytimg.com/vi/qtWbQh7wQSs/hqdefault.jpg" alt="" width="480" height="360" loading="lazy" decoding="async">
    <span class="yt-play" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 5.2v13.6L19 12z"/></svg></span>
    <span class="yt-title">【工程師下班有約 EP04】沒有白走的路！如何找到自己的天賦</span>
  </a>
</div>

<p><strong>如果用盡全力還看不到成果，就代表自己沒有天賦嗎？</strong></p>
<p>大一到大三，我參加了 23 場比賽，但一場都沒贏過，甚至連個參加獎都沒有，血淋淋的現實彷彿在告訴我：「你，不過如此。」</p>
<p>但我沒有選擇放棄，而是持續尋找新的可能性；最終在大四那年，我找到適合自己的路！</p>
<p>有時你不是沒有天賦，只是嘗試的領域不夠多；或者跟我一樣，複合領域才是我們大顯身手的地方！</p>
<h2 id="人與人之間存在天賦上的差距">人與人之間，存在天賦上的差距<a class="h-anchor" href="#%e4%ba%ba%e8%88%87%e4%ba%ba%e4%b9%8b%e9%96%93%e5%ad%98%e5%9c%a8%e5%a4%a9%e8%b3%a6%e4%b8%8a%e7%9a%84%e5%b7%ae%e8%b7%9d" aria-label="這個段落的連結"></a></h2>
<hr>
<p>儘管很多雞湯文都說天賦的差距可以靠努力突破，但在現實世界中，僅有極少數的人能夠辦到。</p>
<p>因為我是電機轉資工，所以程式基礎比班上那些資訊科出身的同學薄弱很多。</p>
<p>而班上大概有 10 個人是選手出身，我在他們身上看到了所謂的「天賦」。</p>
<p>比如遇到難題的時候，大部分人是去「尋找」解決方案，而他們是直接「想到」解決方案。</p>
<p>當然你可能會說，這是經驗累積的成果。</p>
<p>但業界其實有不少工作 10 年以上的資深工程師，儘管花了很多時間「尋找」；但最終還是沒有找到合適的解決方案，因為有時解決方案是需要自己「創造」的。</p>
<p>而我是一個好勝心很強的人，為了測試自己用盡全力能離選手多近</p>
<p>在大一上學期，我每天花 8 小時寫程式、刷題，在第一次 C 語言的上機考就拿到 93 分的成績。</p>
<p>93 分在班上算前段班了，但上機考的分數呈現 M 型分佈，不是不及格，就是85分以上。</p>
<p>而這個 M 型化並沒有隨著時間推移改變，即使是資工系，有些人直到畢業還是不太會寫程式，轉系留級都是常態。</p>
<p>如果螢幕前的朋友想要選擇工程師這條路，我想提醒大家：<strong>『程式是很殘酷的，結果不是 0 就是 1，只要沒結果，你中間的努力都不算數。』</strong></p>
<p>不過這段努力的時光讓我認知到，只要夠努力，我在程式方面還算擁有「不上不下」的天賦，至少未來有辦法靠這項技能混口飯吃。</p>
<p>講到這邊，我腦中突然冒出一句話：<strong>『別人考 100 分，是因為滿分只有 100 分；你考 93 分，是因為你的實力只到 93 分。』</strong></p>
<p>下面放上朋友跟我的一段對話，在有天賦的人眼中，除了第一名外，其他都是參加獎。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/line_hu_50e4ee1a905b1931.webp" width="968" height="1243" alt="與朋友的 LINE 對話：別人沒贏是沒獎狀，他是沒拿第一" fetchpriority="high" decoding="async"></p>
<h2 class="h-nomark" id="3-年-23-場比賽我連一場都沒贏過">3 年 23 場比賽，我連一場都沒贏過<a class="h-anchor" href="#3-%e5%b9%b4-23-%e5%a0%b4%e6%af%94%e8%b3%bd%e6%88%91%e9%80%a3%e4%b8%80%e5%a0%b4%e9%83%bd%e6%b2%92%e8%b4%8f%e9%81%8e" aria-label="這個段落的連結"></a></h2>
<hr>
<p>了解自己程式方面的天賦後，我開始做一些「不務正業」的嘗試。</p>
<p>因為高職參加各種比賽都獲得不錯成績，尤其在文學領域幾乎戰無不勝，所以我產生了迷之自信，認為自己在文學方面肯定天賦異稟。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/award_hu_1a37d3e14e2e4ffc.webp" width="1440" height="709" alt="高職時期參加文學等競賽獲得的數十張獎狀" loading="lazy" decoding="async"></p>
<p>於是我積極參加各種文學競賽，只要主題有「散文、小說」我就去比。</p>
<p>從大一到大三，大大小小共參加 23 場比賽，甚至在 19 歲就寫完一本 10 萬字小說。</p>
<p>但結果呢？比賽不僅全部落榜，連投稿到出版社的小說也都石沈大海。</p>
<p>連續 3 年的失敗，讓我深刻體會到：<strong>『過去之所以會贏，是因為選對了對手；現在之所以會輸，是因為選錯了對手。』</strong></p>
<h2 id="專項贏不了就嘗試複合領域">專項贏不了，就嘗試複合領域<a class="h-anchor" href="#%e5%b0%88%e9%a0%85%e8%b4%8f%e4%b8%8d%e4%ba%86%e5%b0%b1%e5%98%97%e8%a9%a6%e8%a4%87%e5%90%88%e9%a0%98%e5%9f%9f" aria-label="這個段落的連結"></a></h2>
<hr>
<p>大四為了湊滿選修學分，我修了「創業管理」這門課。</p>
<p>如果只看課名，應該很多人會覺得這是門「聽演講混學分」的課程；但在聽完第一堂課程大綱說明後，我便意識到這是門「非常累」的課程，因此有超過一半的人在第二堂課直接退選。</p>
<p>這堂課累的地方在於，「創業管理」是跟你玩真的！</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/school_hu_b104e6b9945694e0.webp" width="960" height="720" alt="北科大與海洋大學跨校競賽的師生大合照" loading="lazy" decoding="async"></p>
<p>除了每個禮拜都要小組競賽報告進度外，還要輪流當主持人、場地佈置、會議紀錄、影片拍攝、網頁發表，甚至還要經營粉絲專頁。</p>
<p>到了學期中要多次跨校競賽，而學期末甚至要把產品實體化做成果發表。</p>
<p>為了讓每個小組成員都有各自擅長的領域，老師把一個系的同學強制打散，所以大家都不認識，非常考驗社交和溝通能力。</p>
<p>以結果來說，我很感謝當時選修這門課，還修了兩次。</p>
<p>它讓我在出社會前，了解什麼是跨部門溝通、團隊領導統御、產品發表技巧，也讓我意識到自己真正適合的領域。</p>
<p>我很清楚，在「技術、文學、管理」任何一個領域，我都達不到頂尖。</p>
<p><strong>但如果把競爭項目改為「技術+文學+管理」，我的綜合戰力就會上升非常多，甚至能跟頂尖團隊一較高下。</strong></p>
<h2 id="只要你還沒放棄其他人也會被影響">只要你還沒放棄，其他人也會被影響<a class="h-anchor" href="#%e5%8f%aa%e8%a6%81%e4%bd%a0%e9%82%84%e6%b2%92%e6%94%be%e6%a3%84%e5%85%b6%e4%bb%96%e4%ba%ba%e4%b9%9f%e6%9c%83%e8%a2%ab%e5%bd%b1%e9%9f%bf" aria-label="這個段落的連結"></a></h2>
<hr>
<p>其實「創業管理」這堂課修起來，比想像中的「更累」且「更不順利」。</p>
<p>過去比賽都是單打獨鬥，突然變成團隊作戰有很多需要學習的，比如：</p>
<ol>
<li>每個人來自不同系，想法很難統一</li>
<li>而且每個人修課理由不同，你想得名，但其他人可能只想躺平</li>
<li>因為彼此不熟，在缺乏連結的狀態下，有些組員說失蹤就失蹤</li>
<li>另外在團隊出現大家都認可的領導者前，合作會相當混亂</li>
</ol>
<p>第一次修課時，我是團隊中對比賽最感興趣的人，其他成員雖然不到不感興趣，但也不想花太多時間準備。</p>
<p>隨著時間推移，這個狀況越來越嚴重，而且磨合的過程未必會解決問題，有時還會製造出更多問題。</p>
<p>當時距離期末剩沒幾個禮拜，如果問題再不解決，基本上就是等著翻船了。</p>
<p>這個學期我們的提案是用樂高拼裝的概念，做出不同功能的旅行分裝罐。</p>
<p>一開始請有製作模型專業背景的組員協助，結果到正式 Demo 的前一天</p>
<p>他突然說遇到技術問題無法 3D 列印，因為連組內的專業人士都放棄了，所以其他成員就選擇躺平。</p>
<p>但我偏偏就是那種「就算所有人都放棄希望，我還是會一個人堅持到底」的性格。</p>
<p>儘管沒有製作模型經驗，我還是去文具店買保麗龍，自己手工切割、用色紙包裝，一直弄到天亮才完工。</p>
<p>圖片桌上這些看起來像是小學生勞作的東西，就是當年創業競賽的產品原型。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/mock_hu_f3e59805c19d8d80.webp" width="1440" height="810" alt="保麗龍與色紙手工製作的旅行分裝罐原型" loading="lazy" decoding="async"></p>
<p>這次經驗讓我體會到：<strong>『不是因為看到希望才選擇堅持，而是因為堅持所以才看到希望。』</strong></p>
<p>儘管成品外觀不太理想，但我那晚的努力直接改變了團隊氣氛。 因為局面已經從「穩輸」變成「有機會贏」，人在有希望的時候往往願意多努力一點。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/game_hu_6a69cfa19354f36a.webp" width="1440" height="931" alt="向評審展示旅行分裝罐原型的比賽現場" loading="lazy" decoding="async"></p>
<p>而團隊很幸運在隔天比賽獲得第一名。</p>
<p>從這次勝利開始，團隊凝聚力越來越強，接下來每週比賽也成為常勝軍，最終在跨校競賽取得了第二名的成績。</p>
<p>而在下學期的課程，我受邀擔任課堂助教，讓我用不同的身份與視角，帶領團隊取得成績。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/team_hu_fe820950217b5637.webp" width="1131" height="980" alt="創業管理課團隊在樓梯上張開雙臂合影" loading="lazy" decoding="async"></p>
<p>也許比賽規模不大，獎金不多，但他讓我找到了適合自己的位置。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice2-hard-work-talent-or-timing/young_hu_7034f9779923e8f8.webp" width="1058" height="1104" alt="手持海洋大學與北科大跨校創業競賽的獎金看板" loading="lazy" decoding="async"></p>
<h2 id="沒有白走的路">沒有白走的路<a class="h-anchor" href="#%e6%b2%92%e6%9c%89%e7%99%bd%e8%b5%b0%e7%9a%84%e8%b7%af" aria-label="這個段落的連結"></a></h2>
<hr>
<p>很多事情在把時間拉長後，你才會發覺當時的努力是有意義的：</p>
<ul>
<li><strong>➤ 文學</strong>：儘管我文學獎一次都沒有贏過，但當我把寫腳本的概念，應用到產品發表上時，就能讓每個組員清楚要講的話和扮演的角色，保證上台穩定度和 Demo 品質。</li>
<li><strong>➤ 技術</strong>：雖然大四技術水平有限，但理工底子讓我能判斷方案可行性，並有能力把產品的原型製作出來。</li>
<li><strong>➤ 管理</strong>：縱然我過去沒有領導統御經驗，但在團隊成員都不積極的狀態下，努力做事的人就會自然成為領導者。這個道理出社會也一樣。</li>
</ul>
<p>很多人出社會後還是找不到自己的定位。</p>
<p>我覺得有時找不到定位，是因為接觸的領域不夠多，缺乏比較基準。</p>
<p>而所謂「天賦」也不一定只侷限在單一領域，有時複合領域才是你大顯身手的地方。</p>
<p>如果你還在尋找方向，不妨多嘗試不同領域，也許你會發現，那些看似白走的路，其實都在為你的未來鋪路。</p>
<hr>
<p>我是鼎淵，一個熱愛分享 AI 知識、自我成長、職涯發展主題的工程師。</p>
<p>歡迎追蹤<a href="https://www.youtube.com/@dlcorner">我的 YouTube</a>，帶你掌握時代趨勢！</p>
<blockquote>
<p>《工程師下班有約》網路書店： 🐲<a href="https://www.tenlong.com.tw/products/9786264142083">天瓏書局</a></p>
</blockquote>
<hr>
<blockquote>
<p>我是林鼎淵，如果覺得這邊文章對你有幫助，歡迎追蹤筆者的 <a href="https://www.facebook.com/deanlinbao">Facebook</a> 與 <a href="https://www.youtube.com/@dlcorner">YouTube</a>，我會持續分享實用的新知識 💡</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>如何透過差異化競爭累積自信</title>
      <link>https://deanlin.net/blog/202508/afteroffice1-vhs-changed-my-life/</link>
      <pubDate>Fri, 01 Aug 2025 22:07:47 +0800</pubDate>
      <guid>https://deanlin.net/blog/202508/afteroffice1-vhs-changed-my-life/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>大安高工是我夢想的起點，我就是在這裡領悟到「差異化競爭」的重要性；甚至可以這麼說，如果當年上的是普通高中，我現在可能極其平凡。我們絕大多數人都是普通人，沒有過人的天賦，無論多努力也贏不過那些天才。興趣與自信不是與生俱來，而是建立在一次次的勝利之上。選對環境，人生真的可以走捷徑！</description>
      <media:content url="https://deanlin.net/images/post/202508/afteroffice1-vhs-changed-my-life/cover_hu_bafe87c8650df588.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<div class="yt" data-yt="bRu_-Uxt3y0" data-title="【工程師下班有約 EP03】如何透過差異化競爭累積自信">
  <a class="yt-link" href="https://www.youtube.com/watch?v=bRu_-Uxt3y0" target="_blank" rel="noopener" aria-label="播放影片：【工程師下班有約 EP03】如何透過差異化競爭累積自信">
    <img src="https://i.ytimg.com/vi/bRu_-Uxt3y0/hqdefault.jpg" alt="" width="480" height="360" loading="lazy" decoding="async">
    <span class="yt-play" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 5.2v13.6L19 12z"/></svg></span>
    <span class="yt-title">【工程師下班有約 EP03】如何透過差異化競爭累積自信</span>
  </a>
</div>

<p><strong>大安高工是我夢想的起點，我就是在這裡領悟到「差異化競爭」的重要性。</strong></p>
<p>甚至可以這麼說，如果當年上的是普通高中，我現在可能極其平凡。</p>
<p>就讓我透過這篇文章，跟大家分享我人生中的轉捩點吧。</p>
<h2 id="你不用很強但要夠特別">你不用很強，但要夠特別<a class="h-anchor" href="#%e4%bd%a0%e4%b8%8d%e7%94%a8%e5%be%88%e5%bc%b7%e4%bd%86%e8%a6%81%e5%a4%a0%e7%89%b9%e5%88%a5" aria-label="這個段落的連結"></a></h2>
<hr>
<p><strong>雖然不想承認，但我們絕大多數都是普通人，沒有過人的天賦，無論多努力也贏不過天才。</strong></p>
<p>我在發現自己的極限後，儘管分數能上公立高中，但還是選擇了讀高職。</p>
<p>上高職後，因為沒什麼學業壓力，所以放學後都在玩電動、看動畫，不過家人希望我不要整天無所事事。</p>
<p>但我並不是一個喜歡念書的學生，為了找點事讓自己看起來很認真，我跑去考不同科系的證照。</p>
<p><strong>然後短短兩個月，就考了 6 張證照。</strong></p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice1-vhs-changed-my-life/certificate_hu_9606cee78a1aa368.webp" width="1440" height="653" alt="兩個月內考取的 6 張丙級技術士證" fetchpriority="high" decoding="async"></p>
<p>不過說實話，丙級證照只要熟悉術科、背好學科，考試的難度並不高。</p>
<p>但真的去考這麼多張證照的人並不多，因為就算考到了，對升學、職涯並沒有多大幫助。</p>
<p>但就因為這個特別的舉動，我獲得了意想不到的「機會」。</p>
<h2 id="獲得機會跟掌握機會是兩件事">獲得機會，跟掌握機會是兩件事<a class="h-anchor" href="#%e7%8d%b2%e5%be%97%e6%a9%9f%e6%9c%83%e8%b7%9f%e6%8e%8c%e6%8f%a1%e6%a9%9f%e6%9c%83%e6%98%af%e5%85%a9%e4%bb%b6%e4%ba%8b" aria-label="這個段落的連結"></a></h2>
<hr>
<p>大多數丙級證照的通過率都超過 75%，但也有少部份的證照難度較高。</p>
<p>其中「電腦軟體設計」是我印象最深的證照，因為我參加的那場通過率只有 17%。</p>
<p>也因為這張證照，我因緣際會地認識了當時擔任圖書館主任的許益財老師，他是我一生的貴人。</p>
<p>他把我轉介給「電腦研究社」的指導老師，並推薦我成為當年「台北市電腦軟體設計競賽」的選手。</p>
<p>收到這個邀請的時候，我是想要拒絕的，因為我之所以能考到這張證照，是因為把術科全部的程式碼都背下來了。</p>
<p>不過聽到參加比賽就可以不用上課，還有一個場地讓選手集中培訓後，我就決定參賽了。</p>
<p>因為對我來說，「不上課」跟「當選手」這兩件事很特別，比上課讀書更有吸引力。</p>
<p>這個比賽分為「初賽」和「決賽」兩個階段，因為初賽只有筆試，所以我輕鬆過關。</p>
<p>而決賽則是要在現場寫程式解題，儘管經過一段時間的特訓，但臨時抱佛腳顯然在正式比賽中沒多大用處。</p>
<p>在 3 個小時過去後，我毫無懸念地成為這場比賽的炮灰。</p>
<h2 id="嘗試帶來見識見識帶來膽識">嘗試帶來見識，見識帶來膽識<a class="h-anchor" href="#%e5%98%97%e8%a9%a6%e5%b8%b6%e4%be%86%e8%a6%8b%e8%ad%98%e8%a6%8b%e8%ad%98%e5%b8%b6%e4%be%86%e8%86%bd%e8%ad%98" aria-label="這個段落的連結"></a></h2>
<hr>
<p>儘管個人賽變成了炮灰，但當年的團體賽，我靠隊友拿到了第一名，這是我第一次體會到「抱大腿」的重要性。</p>
<p>你未必要成為團隊中最強的人，但一定要進入強者的圈子。</p>
<p>另外我在這場比賽中，有三個重要體悟：</p>
<p><strong>第一，多學幾項技能，有時會獲得意外的機會。</strong></p>
<p><strong>第二，運氣可以讓你獲得機會，但沒有實力，給你再多的機會也沒有用處。</strong></p>
<p><strong>第三，透過比賽認識的「人脈」，有時比同學間的情誼更加深刻。</strong></p>
<p>這場比賽我最大的機緣是認識「楊凱霖」學長，如果沒有他，我大學應該不會從電機轉到資工。</p>
<h2 id="人需要一場勝利然後記住這個感覺">人，需要一場勝利，然後記住這個感覺<a class="h-anchor" href="#%e4%ba%ba%e9%9c%80%e8%a6%81%e4%b8%80%e5%a0%b4%e5%8b%9d%e5%88%a9%e7%84%b6%e5%be%8c%e8%a8%98%e4%bd%8f%e9%80%99%e5%80%8b%e6%84%9f%e8%a6%ba" aria-label="這個段落的連結"></a></h2>
<hr>
<p>比賽輸了後，我又回歸平凡的人生；直到某天經過圖書館時，剛好看到同班同學在跟一位老師討論小論文比賽的最終版本。</p>
<p>等同學與老師討論完後，我不知道哪根筋不對，突然向老師詢問：「請問您可以當我小論文的指導老師嗎？」</p>
<p>老師應該也被這個問題嚇到了，因為這是我們第一次見面，連彼此的名字都不知道，而且「隔天」就是比賽的截稿日。</p>
<p>但與老師了解完比賽的規則後，我還是決定參賽了。</p>
<p>當時我甚至連題目都還沒想好，其實這個決定現在回想起來依舊非常不可思議。</p>
<p>而這場比賽我只花了一個晚上完成草稿，並在隔天利用下課時間詢問老師的建議，等放學優化完細節後就直接上傳檔案了。</p>
<p>當時我對這場比賽不抱任何希望，畢竟只是一時的隨興參與，沒有得獎也是理所當然；結果沒想到，公佈成績時竟然得獎了！</p>
<p>這邊要特別感謝周佳嵐老師給予的協助，如果當時被拒絕，也許我現在的命運就不一樣了。</p>
<p>這個獎對我的人生來說，真的意義非凡；因為在這之前，我這輩子從來沒有在任何比賽中拿過個人獎項，它幫我打了一劑強心針。</p>
<p><strong>不管後續贏了多少場比賽，我都不會忘記這個「起點」。</strong></p>
<p>而且因為這次有得獎，原本希望我乖乖讀書的家人，更願意讓我做多方嘗試。</p>
<p>並且在獲得第一場勝利後，我開始對對比賽上癮；接下來的高職生涯都在參加各種競賽、活動。</p>
<p>從圖片來看，這戰績應該還算小有成就。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice1-vhs-changed-my-life/award_hu_1a37d3e14e2e4ffc.webp" width="1440" height="709" alt="高職時期拿到的數十張獎狀，包含臺北市長獎" loading="lazy" decoding="async"></p>
<p>別人拿市長獎是因為成績第一，但我拿市長獎，是因為贏得的比賽夠多。</p>
<h2 id="興趣與自信是建立在一次次的勝利之上">興趣與自信，是建立在一次次的勝利之上<a class="h-anchor" href="#%e8%88%88%e8%b6%a3%e8%88%87%e8%87%aa%e4%bf%a1%e6%98%af%e5%bb%ba%e7%ab%8b%e5%9c%a8%e4%b8%80%e6%ac%a1%e6%ac%a1%e7%9a%84%e5%8b%9d%e5%88%a9%e4%b9%8b%e4%b8%8a" aria-label="這個段落的連結"></a></h2>
<hr>
<p>但提醒一下大家，除非你很有天賦，不然請從小型比賽開始參加。</p>
<p>在初期累積自信是最重要的事，如果努力看不到成果，任何事情都很難堅持下去。</p>
<p>這讓我想到台灣桌球名將「林昀儒」的故事，他小時候受訪時被問到為什麼喜歡打桌球。</p>
<p><img src="https://deanlin.net/images/post/202508/afteroffice1-vhs-changed-my-life/table_tennis_hu_1afc53eec72bfa6f.webp" width="800" height="450" alt="林昀儒童年受訪畫面，字幕「因為都會贏啊」" loading="lazy" decoding="async"></p>
<p>他的回答是：「因為都會贏啊，呵呵」。</p>
<p><strong>興趣與自信不是與生俱來，而是建立在一次次的勝利之上。</strong></p>
<p>另外我之所以能拿到這麼多獎狀，也是多虧了貴人的提點。</p>
<p>當時在學校擔任輔導室主任的林浥雰老師，不僅指導了我生涯學習檔案的製作，更讓我從高中開始，就「有意識」的在累積自己各方面的履歷，這個概念也讓我受用終生。</p>
<h2 id="人少的路能看到不同的風景">人少的路，能看到不同的風景<a class="h-anchor" href="#%e4%ba%ba%e5%b0%91%e7%9a%84%e8%b7%af%e8%83%bd%e7%9c%8b%e5%88%b0%e4%b8%8d%e5%90%8c%e7%9a%84%e9%a2%a8%e6%99%af" aria-label="這個段落的連結"></a></h2>
<hr>
<p>曾經有人將大安高工比喻為高職界的建中。</p>
<p>也許這樣說會讓有些人感到不適，但比賽不只看你有多強，還要看你的對手是誰。</p>
<p>所謂「差異化競爭」，就是讓你在人群中引人注目的方法，比如：</p>
<ul>
<li>我在重視成績的班級不讀書跑去考證照</li>
<li>明明讀的是讀電機科，卻參加資訊科的比賽</li>
<li>在人文沙漠的高職，去橫掃文學競賽的獎項</li>
</ul>
<p>「違反常理、與眾不同的舉動」能讓普通人獲得不少優勢，在高職的比賽中，你不用有太高的天賦，只要肯下苦工，就能贏過大部分的人。</p>
<p>在這裡，只要付出努力，就能看到成果！</p>
<p>儘管我上學期間不務正業、畢業時班排倒數，但還是有考上北科。</p>
<p>而當時班上有超過 2/3 的同學錄取臺科、北科。</p>
<p>其實當年考基測時，我們都可以上公立高中，但這種不上不下的水平，之後想考國立大學還是得努力讀書。</p>
<p>不過如果選擇讀高職，我們就可以輕鬆成為競爭環境中的佼佼者，<strong>選對環境，人生真的可以走捷徑。</strong></p>
<hr>
<p>我是鼎淵，一個熱愛分享 AI 知識、自我成長、職涯發展主題的工程師。</p>
<p>歡迎追蹤<a href="https://www.youtube.com/@dlcorner">我的 YouTube</a>，帶你掌握時代趨勢！</p>
<blockquote>
<p>《工程師下班有約》網路書店： 🐲<a href="https://www.tenlong.com.tw/products/9786264142083">天瓏書局</a></p>
</blockquote>
<hr>
<blockquote>
<p>我是林鼎淵，如果覺得這邊文章對你有幫助，歡迎追蹤筆者的 <a href="https://www.facebook.com/deanlinbao">Facebook</a> 與 <a href="https://www.youtube.com/@dlcorner">YouTube</a>，我會持續分享實用的新知識 💡</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>我用 Vibe Coding 寫了一個線上提詞機</title>
      <link>https://deanlin.net/blog/202507/afteroffice8-vibe-coding/</link>
      <pubDate>Tue, 22 Jul 2025 22:07:47 +0800</pubDate>
      <guid>https://deanlin.net/blog/202507/afteroffice8-vibe-coding/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>AI 實戰</category>
      <description>開始拍 YouTube 影片後，因為我總是記不住台詞，所以需要提詞機。但免費版廣告一堆，付費版又塞了一堆用不到的功能。既然如此，我乾脆直接用 Vibe Coding 寫一款無廣告的提詞機給大家免費使用！</description>
      <media:content url="https://deanlin.net/images/post/202507/afteroffice8-vibe-coding/cover_hu_f47083c5dcf4d4d9.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<div class="yt" data-yt="tQZXzb88jmo" data-title="給我 1 分鐘，帶你認識現在最夯的 Vibe Coding #ai #aicoding #vibecoding #chatgpt #cursor #githubpages">
  <a class="yt-link" href="https://www.youtube.com/watch?v=tQZXzb88jmo" target="_blank" rel="noopener" aria-label="播放影片：給我 1 分鐘，帶你認識現在最夯的 Vibe Coding #ai #aicoding #vibecoding #chatgpt #cursor #githubpages">
    <img src="https://i.ytimg.com/vi/tQZXzb88jmo/hqdefault.jpg" alt="" width="480" height="360" loading="lazy" decoding="async">
    <span class="yt-play" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 5.2v13.6L19 12z"/></svg></span>
    <span class="yt-title">給我 1 分鐘，帶你認識現在最夯的 Vibe Coding #ai #aicoding #vibecoding #chatgpt #cursor #githubpages</span>
  </a>
</div>

<p>開始拍 YouTube 影片後，因為我總是記不住台詞，所以需要提詞機；但免費版廣告一堆，付費版又塞了一堆用不到的功能。</p>
<p>既然如此，我乾脆直接用 Vibe Coding 寫一款<a href="https://deanlin.net/teleprompter/">無廣告的提詞機</a>給大家免費使用！</p>
<h2 id="工具選擇">工具選擇<a class="h-anchor" href="#%e5%b7%a5%e5%85%b7%e9%81%b8%e6%93%87" aria-label="這個段落的連結"></a></h2>
<hr>
<p>一開始我先用 ChatGPT 來寫程式，但隨著需求增加，他開始鬼打牆；不但新功能沒做好，連原本能用的也壞了。</p>
<p>就算提示詞加上各種限制，或開新的對話窗，也沒太大幫助。</p>
<p><img src="https://deanlin.net/images/post/202507/afteroffice8-vibe-coding/limit_hu_17503d0cd3295a01.webp" width="650" height="410" alt="向 ChatGPT 提出三項修改，並要求其他部分勿更新" fetchpriority="high" decoding="async"></p>
<p><strong>所以在 Vibe Coding 的工具選擇上，我並不推薦使用 ChatGPT。</strong></p>
<p>我個人更推薦使用的工具是 <a href="https://cursor.com/cn">Cursor</a>，他是一款內建 AI 功能的程式碼編輯器。</p>
<p><img src="https://deanlin.net/images/post/202507/afteroffice8-vibe-coding/cursor_hu_377b7d5a0c64e2ca.webp" width="1440" height="827" alt="Cursor 編輯器開啟提詞機專案與 AI 對話面板" loading="lazy" decoding="async"></p>
<p>可以使用中文與他溝通，且每次修改都有差異比較。</p>
<p>不論新手學程式或老手解 bug，Cursor 都比 ChatGPT 高效。</p>
<h2 id="使用提醒">使用提醒<a class="h-anchor" href="#%e4%bd%bf%e7%94%a8%e6%8f%90%e9%86%92" aria-label="這個段落的連結"></a></h2>
<hr>
<p>但還是要提醒大家，AI 雖能加速開發，卻不保證一次到位。</p>
<p>如果你有程式的底子，那提出具體問題、給予明確方向，可以大幅縮短開發時程。</p>
<p>沒有程式基礎的也別擔心，先請 AI 解釋邏輯、逐步拆解，你一樣能從 0 打造自己的工具。</p>
<p>不過 Vibe Coding 雖然聽起來輕鬆，但背後仍需要反覆測試，以及對錯誤訊息保持耐心。</p>
<blockquote>
<p>AI 是助力，不是萬能！</p>
</blockquote>
<h2 id="成果展示">成果展示<a class="h-anchor" href="#%e6%88%90%e6%9e%9c%e5%b1%95%e7%a4%ba" aria-label="這個段落的連結"></a></h2>
<hr>
<p>如果你 Vibe Coding 的作品是靜態網頁，上傳到 GitHub Pages 就能向大家展示自己的成果。</p>
<p><img src="https://deanlin.net/images/post/202507/afteroffice8-vibe-coding/github_pages_hu_5ca0087b12002ac.webp" width="1208" height="839" alt="GitHub Pages 官方網站首頁" loading="lazy" decoding="async"></p>
<p>我完成的題詞器，以及上面提到的工具連結如下，歡迎取用：</p>
<ul>
<li><strong>讀稿提詞機</strong>: <a href="https://deanlin.net/teleprompter/">https://deanlin.net/teleprompter/</a></li>
<li><strong>ChatGPT</strong>: <a href="https://chatgpt.com/">https://chatgpt.com/</a></li>
<li><strong>Cursor</strong>: <a href="https://cursor.com/cn">https://cursor.com/cn</a></li>
<li><strong>GitHub</strong>: <a href="https://github.com/">https://github.com/</a></li>
</ul>
<p>如果你對這個主題感興趣，可以幫我點個讚。</p>
<p>我是鼎淵，一個熱愛分享 AI 知識、自我成長、職涯發展主題的工程師。</p>
<p>歡迎追蹤<a href="https://www.youtube.com/@dlcorner">我的 YouTube</a>，帶你掌握時代趨勢！</p>
<blockquote>
<p>《工程師下班有約》網路書店： 🐲<a href="https://www.tenlong.com.tw/products/9786264142083">天瓏書局</a></p>
</blockquote>
<hr>
<blockquote>
<p>我是林鼎淵，如果覺得這邊文章對你有幫助，歡迎追蹤筆者的 <a href="https://www.facebook.com/deanlinbao">Facebook</a> 與 <a href="https://www.youtube.com/@dlcorner">YouTube</a>，我會持續分享實用的新知識 💡</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>過度美化未來，容易讓人做出衝動的選擇</title>
      <link>https://deanlin.net/blog/202507/afteroffice7-imagination-and-reality-ep02/</link>
      <pubDate>Thu, 17 Jul 2025 22:07:47 +0800</pubDate>
      <guid>https://deanlin.net/blog/202507/afteroffice7-imagination-and-reality-ep02/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>通常鼓勵你勇敢追夢的人，都是那些已經實現夢想的人，這本身就是一種倖存者偏差。你的人生只有自己能負責，千萬不要盲目追隨。如果你沒有興趣只是一昧地模仿，最終反而會失去自己的風格。</description>
      <media:content url="https://deanlin.net/images/post/202507/afteroffice7-imagination-and-reality-ep02/cover_hu_7ba4005ed3ff51d8.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<div class="yt" data-yt="yceR8Wy43No" data-title="【工程師下班有約 EP02】過度美化未來，容易讓人做出衝動的選擇">
  <a class="yt-link" href="https://www.youtube.com/watch?v=yceR8Wy43No" target="_blank" rel="noopener" aria-label="播放影片：【工程師下班有約 EP02】過度美化未來，容易讓人做出衝動的選擇">
    <img src="https://i.ytimg.com/vi/yceR8Wy43No/hqdefault.jpg" alt="" width="480" height="360" loading="lazy" decoding="async">
    <span class="yt-play" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 5.2v13.6L19 12z"/></svg></span>
    <span class="yt-title">【工程師下班有約 EP02】過度美化未來，容易讓人做出衝動的選擇</span>
  </a>
</div>

<p>在 2022 年出版《<a href="https://www.books.com.tw/products/0010955655">給全端工程師的職涯生存筆記</a>》後，收到母校的邀請，讓我與學弟妹分享自己的故事。</p>
<p>因為距離學生時代還不算太遙遠，所以我很清楚以前在當學生時，常常台上講得熱血激昂，而台下睡成一片；偶爾清醒，也不過是為了應付要繳交的演講心得。</p>
<p>為了盡可能避免這樣的場景發生，我決定先回母校一趟。</p>
<h2 id="不要只把演講當履歷要讓它對觀眾有意義">不要只把演講當履歷，要讓它對觀眾有意義<a class="h-anchor" href="#%e4%b8%8d%e8%a6%81%e5%8f%aa%e6%8a%8a%e6%bc%94%e8%ac%9b%e7%95%b6%e5%b1%a5%e6%ad%b7%e8%a6%81%e8%ae%93%e5%ae%83%e5%b0%8d%e8%a7%80%e7%9c%be%e6%9c%89%e6%84%8f%e7%be%a9" aria-label="這個段落的連結"></a></h2>
<hr>
<p>到校與老師詳聊後，我發現這是一個「職場達人週」的活動，會邀請幾位業界人士到校分享；希望讓學生初步了解不同產業的實際面貌。</p>
<p>主辦這場活動的老師特別跟我強調，這是場「自由報名」的演講，所以來參加的學生，是真的對演講主題感興趣的。</p>
<p>他們想透過講者的經驗來判斷，這個職涯是否符合自己的期待，跟過去的想像有多大的落差；因此千萬不要抱持應付了事的心態做準備，不要只把這場演講當成履歷的一行字，要讓它對觀眾有意義。</p>
<p>其中一位資深教師還拉著我的手，語重心長的說：「老師跟學生的距離，有時比學長與學弟的距離更遠。對你來說，這是一場演講；但對他們來說，也許會把你當成自己未來的投影。」</p>
<h2 id="過度美化未來容易讓人做出衝動的選擇">過度美化未來，容易讓人做出衝動的選擇<a class="h-anchor" href="#%e9%81%8e%e5%ba%a6%e7%be%8e%e5%8c%96%e6%9c%aa%e4%be%86%e5%ae%b9%e6%98%93%e8%ae%93%e4%ba%ba%e5%81%9a%e5%87%ba%e8%a1%9d%e5%8b%95%e7%9a%84%e9%81%b8%e6%93%87" aria-label="這個段落的連結"></a></h2>
<hr>
<p>我很清楚，故事越精彩，觀眾聽的越認真。</p>
<p>而且能上台分享的業界人士，大多已經在自己的專業領域取得相當的成就。</p>
<p>不過有些人分享的內容太過雞湯，儘管都是真實的生命故事；但很容易讓觀眾產生不切實際的幻想，比如：「成為工程師就能領高薪！」、「我就是因為叛逆才有今天！」、「跟隨心中的想法就能實現夢想！」</p>
<p>高中是一個對未來迷茫，但容易有衝動的年紀；大多數人在這個階段，對每個行業的認知還非常片面，容易只看到好的一面，而忽略選擇背後要付出的代價。</p>
<p>有些行業即使用盡全力也未必能獲得回報，像是人文藝術、競技運動領域。</p>
<p>在這些領域想獲得成就，除了天賦外還需要機緣；也許有人會告訴大家要勇敢追夢，但通常會鼓勵勇敢追夢的人，是因為他已經實現夢想了，這本身就是一種倖存者偏差的狀況。</p>
<p>我不反對追夢，但人要有自知之明；如果發現自己沒有這個潛力，與其定一個有野心的夢想，還不如選一個能實現的目標。</p>
<h2 id="大學讀不到一年就被退學">大學讀不到一年，就被退學<a class="h-anchor" href="#%e5%a4%a7%e5%ad%b8%e8%ae%80%e4%b8%8d%e5%88%b0%e4%b8%80%e5%b9%b4%e5%b0%b1%e8%a2%ab%e9%80%80%e5%ad%b8" aria-label="這個段落的連結"></a></h2>
<hr>
<p>在準備演講的過程中，我跟一位朋友聊了很多，我們都是大安電機科畢業的，如果沒發生意外，我們未來應該都是工程師。</p>
<p>但在高二下學期，他突然對設計產生濃厚的興趣，甚至放棄統測考學測。他是個有天賦的人，儘管準備時間不到半年，還是順利的考上實踐大學設計學院。</p>
<p>冒這麼大風險轉換領域，如果一切順利，他可能也會回學校分享自己的心路歷程；不過很可惜的是，他讀不到一年就被退學了，因為在踏入設計的領域後，他發現這一切跟過去想的完全不一樣。</p>
<p>他原以為藝術是在有靈感的狀態下悠閒創作，但現實告訴他需要在期限內、用指定的框架創作。</p>
<p>但朋友因為過去的基礎不夠扎實，所以要靠熬夜才能勉強趕出作品，但就算如此，他還是經常被退件。</p>
<p>幾個月後，他覺得不管多努力也無法跟上進度，於是開始翹課，過著行屍走肉般的日子直到被退學。</p>
<p>也許有人會想，他放棄統測是因為電機唸不下去嗎？</p>
<p>不！他的班級排名長年維持在前 10，上臺科北科的機率是非常高的。</p>
<p>我分享這個故事，不是要大家放棄追夢，而是想提醒大家：「在認知有限的狀態下，我們容易做出錯誤的選擇。」</p>
<p>以筆者身旁的人而言，大多數勇敢追夢的人，現在生活都過得相對拮据，而且並不快樂。</p>
<h2 id="每個人的人生都是自己選擇而來的">每個人的人生，都是自己選擇而來的<a class="h-anchor" href="#%e6%af%8f%e5%80%8b%e4%ba%ba%e7%9a%84%e4%ba%ba%e7%94%9f%e9%83%bd%e6%98%af%e8%87%aa%e5%b7%b1%e9%81%b8%e6%93%87%e8%80%8c%e4%be%86%e7%9a%84" aria-label="這個段落的連結"></a></h2>
<hr>
<p>我拍這隻影片不是要勸大家放棄夢想，也不是想告訴大家什麼是「正確」的選擇。</p>
<p>因為每個人都是獨立的個體，有不同的學歷、工作、財力、背景，即使做出所謂「正確」的選擇，也未必能獲得一樣的回報。</p>
<p>就像 30 年前買房的難度，跟現在是完全不一樣的；有時一個人的成功並不是他有多努力，只是剛好參與到總體經濟的進步。</p>
<p>但大多數人在分享自己的成功故事時，總是會習慣性的把原因歸咎於「努力」，但很可能一切都只是機緣巧合罷了。</p>
<p>之所跟大家分享失敗案例，是希望能給大家一些「警惕」。</p>
<p>就算你在我日後的影片中，看到很有共鳴的片段、感覺很棒的技巧，也請謹慎評估。</p>
<p>畢竟你的人生只有自己能負責，千萬不要盲目追隨，我也是一個幸存者偏差的案例，適合我的，未必適合你。</p>
<p>在下一隻影片中，我會分享自己高中時期靠差異化競爭累積優勢的技巧。</p>
<p>但我是因為「自己有興趣」才能做的這麼起勁，只是結果剛好讓我累積了與眾不同的優勢。</p>
<p>如果當時是別人逼我這麼做，我是不可能堅持這麼久的。</p>
<p>提醒大家，如果你沒有興趣只是一昧地模仿，最終反而會失去自己的風格。</p>
<p>如果你聽膩了毒雞湯，看膩了公式化的影片，<a href="https://www.youtube.com/@dlcorner">歡迎訂閱我的 YouTube</a>，帶你用不同的視角看世界。</p>
<blockquote>
<p>《工程師下班有約》網路書店： 🐲<a href="https://www.tenlong.com.tw/products/9786264142083">天瓏書局</a></p>
</blockquote>
<hr>
<blockquote>
<p>我是林鼎淵，如果覺得這邊文章對你有幫助，歡迎追蹤筆者的 <a href="https://www.facebook.com/deanlinbao">Facebook</a> 與 <a href="https://www.youtube.com/@dlcorner">YouTube</a>，我會持續分享實用的新知識 💡</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>挑戰，從來不需要獲得別人允許!</title>
      <link>https://deanlin.net/blog/202507/afteroffice6-youtube-start-ep01/</link>
      <pubDate>Sun, 13 Jul 2025 22:07:47 +0800</pubDate>
      <guid>https://deanlin.net/blog/202507/afteroffice6-youtube-start-ep01/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>今年是我經營自媒體的第五年，拍 YouTube 的第一年。沒有人可以一開始就做到完美，但都能做到自己能力範圍內的最好。如果你曾懷疑自己是否走在正確的路上，或者想靠自己的方式重新定義成功，那麼，這裡會是你值得停下腳步的地方。</description>
      <media:content url="https://deanlin.net/images/post/202507/afteroffice6-youtube-start-ep01/cover_hu_a6758d60a602e273.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<div class="yt" data-yt="KnQPPt4l2iE" data-title="【工程師下班有約 EP01】挑戰，從來不需要獲得別人允許">
  <a class="yt-link" href="https://www.youtube.com/watch?v=KnQPPt4l2iE" target="_blank" rel="noopener" aria-label="播放影片：【工程師下班有約 EP01】挑戰，從來不需要獲得別人允許">
    <img src="https://i.ytimg.com/vi/KnQPPt4l2iE/hqdefault.jpg" alt="" width="480" height="360" loading="lazy" decoding="async">
    <span class="yt-play" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 5.2v13.6L19 12z"/></svg></span>
    <span class="yt-title">【工程師下班有約 EP01】挑戰，從來不需要獲得別人允許</span>
  </a>
</div>

<p>今年是我經營自媒體的第五年，拍 YouTube 的第一年。</p>
<p>我們常說自媒體是為自己發聲，但實際上，許多人都是在說別人想聽的話。</p>
<p>大家人都在追求「類似」的審美觀，差不多的價值觀，然後覺得自己「應該」要怎麼做。</p>
<p>我想說能不能來點不一樣的，不追求世俗眼中的正確，去做自己想做的事。</p>
<h2 id="如果沒有行動這世界根本沒有你的時區">如果沒有行動，這世界根本沒有你的時區<a class="h-anchor" href="#%e5%a6%82%e6%9e%9c%e6%b2%92%e6%9c%89%e8%a1%8c%e5%8b%95%e9%80%99%e4%b8%96%e7%95%8c%e6%a0%b9%e6%9c%ac%e6%b2%92%e6%9c%89%e4%bd%a0%e7%9a%84%e6%99%82%e5%8d%80" aria-label="這個段落的連結"></a></h2>
<hr>
<p>在一些雞湯文中，常常會看到這句話：「每個人都有自己的時區。」</p>
<p>很多人在看到這句話之後，就感覺獲得了救贖，在留言區互相取暖。</p>
<p>但我想說的是，除非你選對賽道，而且非常努力，否則你一輩子都不會遇到自己的時區。</p>
<p>我就拿自己當例子吧，早在 2022 年就有拍片的打算，但拖到 2025 年才錄製了<a href="https://youtu.be/KnQPPt4l2iE">第一隻 YouTube 影片</a>。</p>
<h2 id="細節很重要但不要連開始都沒做到">細節很重要，但不要連開始都沒做到<a class="h-anchor" href="#%e7%b4%b0%e7%af%80%e5%be%88%e9%87%8d%e8%a6%81%e4%bd%86%e4%b8%8d%e8%a6%81%e9%80%a3%e9%96%8b%e5%a7%8b%e9%83%bd%e6%b2%92%e5%81%9a%e5%88%b0" aria-label="這個段落的連結"></a></h2>
<hr>
<p>會拖到三年之久，最大的原因是我考慮了太多旁枝末節的事情，像是：</p>
<ul>
<li>是不是要準備好的錄影設備？</li>
<li>現在的背景會不會太隨便？</li>
<li>場地需不需要佈置？</li>
<li>要不要打個燈讓我看起來帥一點？</li>
<li>需不需要學個剪片技巧？</li>
<li>我講這些主題會不會被炮轟？</li>
</ul>
<p>從表面上來看，這些細節都很重要；但也因為這樣，<strong>我連「開始」這件事都沒有做</strong>。</p>
<h2 id="如果沒有這些外在會影響你想呈現的核心價值嗎">如果沒有這些外在，會影響你想呈現的核心價值嗎？<a class="h-anchor" href="#%e5%a6%82%e6%9e%9c%e6%b2%92%e6%9c%89%e9%80%99%e4%ba%9b%e5%a4%96%e5%9c%a8%e6%9c%83%e5%bd%b1%e9%9f%bf%e4%bd%a0%e6%83%b3%e5%91%88%e7%8f%be%e7%9a%84%e6%a0%b8%e5%bf%83%e5%83%b9%e5%80%bc%e5%97%8e" aria-label="這個段落的連結"></a></h2>
<hr>
<p>最後今天拍的這支影片，只有為了收音買了一個麥克風，這是為了保證收音品質，因為我同時也會把這個影片上架到 Podcast。</p>
<p>至於影片的錄製工具，就是用電腦前鏡頭而已。</p>
<p>其實開拍前，我還在糾結：「需不需要化個妝？梳個油頭正式一點？」</p>
<p>但後來我發現，如果我連拍影片這件事情，都要這麼多前置作業，那我應該永遠不會拍。</p>
<p>既然我沒有那麼多時間，那為什麼還要卡在這些表面的東西上？觀眾真的在乎這些細節？</p>
<p>後來我想通了 —— 影片想呈現的不是我的外表，而是我的內容。</p>
<p>我想傳遞的，是那些我準備很久、一直想分享的經驗與知識，這才是最重要的。</p>
<h2 class="h-nomark" id="0-到-1-是突破1-到-100-不過是積累罷了">0 到 1 是突破，1 到 100 不過是積累罷了<a class="h-anchor" href="#0-%e5%88%b0-1-%e6%98%af%e7%aa%81%e7%a0%b41-%e5%88%b0-100-%e4%b8%8d%e9%81%8e%e6%98%af%e7%a9%8d%e7%b4%af%e7%bd%b7%e4%ba%86" aria-label="這個段落的連結"></a></h2>
<hr>
<p>我知道這隻影片還有很多的不足，不管是我的表達能力、剪接能力、拍攝裝備都有很大的進步空間。</p>
<p>但我很清楚，永遠沒有準備好的那一天。</p>
<p>既然如此，為什麼不要大膽嘗試呢？如果沒踏出第一步，想法再好都只是幻想。</p>
<p>我知道很多人不敢踏出第一步，是因為害怕自己的努力毫無意義。</p>
<p>但其實，所有的努力都會留下痕跡，只是不一定受到世俗的認可罷了。</p>
<p>就像這支影片，瀏覽數搞不好連 100 都不到。</p>
<p>但這算失敗嗎？不！對我來說，瀏覽數不是重點，而是我發表了第一隻影片！</p>
<p>我開始嘗試字卡、音效、剪輯，儘管這一切看起來還很粗糙。</p>
<p>起點低，只是代表我還有很大的進步的空間而已。</p>
<h2 id="讓我來當自己的說書人">讓我來當自己的說書人<a class="h-anchor" href="#%e8%ae%93%e6%88%91%e4%be%86%e7%95%b6%e8%87%aa%e5%b7%b1%e7%9a%84%e8%aa%aa%e6%9b%b8%e4%ba%ba" aria-label="這個段落的連結"></a></h2>
<hr>
<p>接下來，我預計會拍 24 隻影片。故事源自於我上個月出版的新書《<a href="https://www.tenlong.com.tw/products/9786264142083">工程師下班有約</a>》。</p>
<p>我會分享一個技職科大體系出身的人，如何連滾帶爬、嘗試一切可能性。</p>
<p>成為現在的外商工程師、暢銷書作家、企業內訓講師。</p>
<p>這一路上，我做過哪些正確的決定，以及踩過哪些原本可以避開的坑。</p>
<p>我沒有要賣夢，只是想聊聊自己走過的路；儘管人生沒有標準答案，但或許我的經驗能給你帶來一些啟發。</p>
<h2 id="挑戰從來不需要獲得別人的允許">挑戰，從來不需要獲得別人的允許<a class="h-anchor" href="#%e6%8c%91%e6%88%b0%e5%be%9e%e4%be%86%e4%b8%8d%e9%9c%80%e8%a6%81%e7%8d%b2%e5%be%97%e5%88%a5%e4%ba%ba%e7%9a%84%e5%85%81%e8%a8%b1" aria-label="這個段落的連結"></a></h2>
<p>其實拍這部影片前，我也在想自己有沒有資格講這些話題。</p>
<p>但後來想想，挑戰，從來不需要獲得別人的允許。</p>
<p>我不知道拍完 24 隻影片後，會不會獲得更多機會，書不會賣得更好。</p>
<p>但我知道，我肯定跟現在的自己不一樣了。</p>
<p>如果你想挑戰過去從沒做過的事情，看見不一樣的觀點，<a href="https://www.youtube.com/@dlcorner">歡迎訂閱我的 YouTube</a>，跟我一起成長。</p>
<blockquote>
<p>《工程師下班有約》網路書店： 🐲<a href="https://www.tenlong.com.tw/products/9786264142083">天瓏書局</a></p>
</blockquote>
<hr>
<blockquote>
<p>我是林鼎淵，如果覺得這邊文章對你有幫助，歡迎追蹤筆者的 <a href="https://www.facebook.com/deanlinbao">Facebook</a> 與 <a href="https://www.youtube.com/@dlcorner">YouTube</a>，我會持續分享實用的新知識 💡</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>用 Python 搭配 OpenAI 的 GPT、Whisper API 取得 Youtube 影片摘要</title>
      <link>https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/</link>
      <pubDate>Mon, 03 Apr 2023 16:56:33 +0800</pubDate>
      <guid>https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>AI 實戰</category>
      <description>如果追求點擊率、按讚數，我應該要用「工程師要失業了！靠 ChatGPT 就能寫出取得 Youtube 影片摘要的程式！」來當標題。但現在還是有不少 ChatGPT 無法解決的問題。這篇文章會用範例讓讀者理解 ChatGPT 在寫程式上的侷限，以及適合使用的場景。</description>
      <media:content url="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-og_hu_1c67dadf8223cb93.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<p>如果追求點擊率、按讚數，我應該要用「工程師要失業了！靠 ChatGPT 就能寫出取得 Youtube 影片摘要的程式！」來當標題。</p>
<p>也許隨著 AI 持續發展，這個標題在未來真的可以實現，但並不是現在。</p>
<p>儘管 ChatGPT 的出現，讓寫程式的門檻大幅降低；但現在還是有不少 ChatGPT 無法解決，或是解決不好的問題。</p>
<p>這篇文章會用範例讓讀者理解 ChatGPT 在寫程式上的侷限，以及適合使用的場景。</p>
<p><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-01.webp" width="1143" height="632" alt="用 Python 搭配 OpenAI 的 GPT、Whisper API 取得 Youtube 影片摘要（圖 1）" fetchpriority="high" decoding="async"></p>
<p><a href="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/">在前面的文章中</a>，筆者已經實現用 Python 將 Youtube 影片轉逐字稿。</p>
<p>而在這篇文章，我將導入 OpenAI 的 GPT API，請他幫我們整理逐字稿，並取得影片摘要。</p>
<blockquote class="pullquote"><p>提醒大家，不要未經授權下載有版權保護的影片喔！</p>
</blockquote>
<h2 id="導入-openai-的-gpt-api提升逐字稿可讀性">導入 OpenAI 的 GPT API，提升逐字稿可讀性<a class="h-anchor" href="#%e5%b0%8e%e5%85%a5-openai-%e7%9a%84-gpt-api%e6%8f%90%e5%8d%87%e9%80%90%e5%ad%97%e7%a8%bf%e5%8f%af%e8%ae%80%e6%80%a7" aria-label="這個段落的連結"></a></h2>
<p>😀：「下面是我用 Python 寫的 Youtube 影片轉成逐字稿的程式，我想要在這個基礎上擴充功能，我在後續的對話中會提出自己的需求，請問你可以幫忙嗎？</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 切割音檔成多個小檔案</span>
</span></span><span style="display:flex;"><span>chunk_size <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">100</span> <span style="color:#ff7b72;font-weight:bold">*</span> <span style="color:#a5d6ff">1000</span>  <span style="color:#8b949e;font-style:italic"># 100 秒</span>
</span></span><span style="display:flex;"><span>chunks <span style="color:#ff7b72;font-weight:bold">=</span> [audio_file[i:i<span style="color:#ff7b72;font-weight:bold">+</span>chunk_size] <span style="color:#ff7b72">for</span> i <span style="color:#ff7b72;font-weight:bold">in</span> range(<span style="color:#a5d6ff">0</span>, len(audio_file), chunk_size)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 使用 OpenAI 的 Audio API 將每個小檔案轉成文字，然後合併在一起</span>
</span></span><span style="display:flex;"><span>openai<span style="color:#ff7b72;font-weight:bold">.</span>api_key <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_API_KEY&#34;</span>
</span></span><span style="display:flex;"><span>transcript <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">for</span> chunk <span style="color:#ff7b72;font-weight:bold">in</span> chunks:
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">with</span> chunk<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;temp.wav&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;wav&#34;</span>) <span style="color:#ff7b72">as</span> f:
</span></span><span style="display:flex;"><span>        result <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>Audio<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;whisper-1&#34;</span>, f)
</span></span><span style="display:flex;"><span>        transcript <span style="color:#ff7b72;font-weight:bold">+=</span> result[<span style="color:#a5d6ff">&#34;text&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 印出轉換後的文字</span>
</span></span><span style="display:flex;"><span>print(transcript)
</span></span></code></pre></div><p><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-02.webp" width="1013" height="238" alt="導入 OpenAI 的 GPT API，提升逐字稿可讀性（圖 2）" loading="lazy" decoding="async"></p>
<p>因為 ChatGPT 的資料截止於 2021 年 9 月，此時的他對於未來世界並不了解，所以我們需要去官方找範例程式，請他協助合併。</p>
<p>這邊我們使用的是 OpenAI 的 Chat 功能：<a href="https://platform.openai.com/docs/api-reference/chat">https://platform.openai.com/docs/api-reference/chat</a></p>
<p>😀：「我找到了一個可以整理逐字稿的套件，官方範例如下，我希望將最後的結果印出來，要如何將他與我現在的程式結合呢？</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">os</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>openai<span style="color:#ff7b72;font-weight:bold">.</span>api_key <span style="color:#ff7b72;font-weight:bold">=</span> os<span style="color:#ff7b72;font-weight:bold">.</span>getenv(<span style="color:#a5d6ff">&#34;OPENAI_API_KEY&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>completion <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>ChatCompletion<span style="color:#ff7b72;font-weight:bold">.</span>create(
</span></span><span style="display:flex;"><span>  model<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;gpt-3.5-turbo&#34;</span>,
</span></span><span style="display:flex;"><span>  messages<span style="color:#ff7b72;font-weight:bold">=</span>[
</span></span><span style="display:flex;"><span>    {<span style="color:#a5d6ff">&#34;role&#34;</span>: <span style="color:#a5d6ff">&#34;user&#34;</span>, <span style="color:#a5d6ff">&#34;content&#34;</span>: <span style="color:#a5d6ff">&#34;Hello!&#34;</span>}
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print(completion<span style="color:#ff7b72;font-weight:bold">.</span>choices[<span style="color:#a5d6ff">0</span>]<span style="color:#ff7b72;font-weight:bold">.</span>message)
</span></span></code></pre></div><p><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-03.webp" width="888" height="666" alt="導入 OpenAI 的 GPT API，提升逐字稿可讀性（圖 3）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-04.webp" width="888" height="657" alt="導入 OpenAI 的 GPT API，提升逐字稿可讀性（圖 4）" loading="lazy" decoding="async"></p>
<p>前面幾篇文章中，我們靠 ChatGPT 就能順利完成專案；但在這篇文章中，<strong>如果你缺乏程式的開發經驗就可能會卡很久</strong>。</p>
<p>首先，<strong>你有沒有發現 ChatGPT 根本不是使用我們提供的官方範例程式！</strong>如果你嘗試跑起來會出現各式各樣的錯誤：</p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-05.webp" width="1400" height="353" alt="這個錯誤是因為他擅自把模型從 gpt-3.5-turbo 改為 davinci 所造成的" loading="lazy" decoding="async">
  <figcaption>這個錯誤是因為他擅自把模型從 gpt-3.5-turbo 改為 davinci 所造成的</figcaption>
</figure>

<p>儘管筆者使用多種方式來調教他，最終也成功試出能夠讓 ChatGPT 吐出正確回應的指令，<strong>但這個指令不具有參考價值，因為我必須描述得非常詳細，如果使用方式太過複雜，那就不是一個值得分享的使用方式</strong>。</p>
<p>所以筆者還是靠自己整合出一個版本：</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 切割音檔成多個小檔案</span>
</span></span><span style="display:flex;"><span>chunk_size <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">100</span> <span style="color:#ff7b72;font-weight:bold">*</span> <span style="color:#a5d6ff">1000</span>  <span style="color:#8b949e;font-style:italic"># 100 秒</span>
</span></span><span style="display:flex;"><span>chunks <span style="color:#ff7b72;font-weight:bold">=</span> [audio_file[i:i<span style="color:#ff7b72;font-weight:bold">+</span>chunk_size] <span style="color:#ff7b72">for</span> i <span style="color:#ff7b72;font-weight:bold">in</span> range(<span style="color:#a5d6ff">0</span>, len(audio_file), chunk_size)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 使用 OpenAI 的 Audio API 將每個小檔案轉成文字，然後合併在一起</span>
</span></span><span style="display:flex;"><span>openai<span style="color:#ff7b72;font-weight:bold">.</span>api_key <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_API_KEY&#34;</span>
</span></span><span style="display:flex;"><span>transcript <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">for</span> chunk <span style="color:#ff7b72;font-weight:bold">in</span> chunks:
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">with</span> chunk<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;temp.wav&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;wav&#34;</span>) <span style="color:#ff7b72">as</span> f:
</span></span><span style="display:flex;"><span>        result <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>Audio<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;whisper-1&#34;</span>, f)
</span></span><span style="display:flex;"><span>        transcript <span style="color:#ff7b72;font-weight:bold">+=</span> result[<span style="color:#a5d6ff">&#34;text&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 整理逐字稿</span>
</span></span><span style="display:flex;"><span>completion <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>ChatCompletion<span style="color:#ff7b72;font-weight:bold">.</span>create(
</span></span><span style="display:flex;"><span>  model<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;gpt-3.5-turbo&#34;</span>,
</span></span><span style="display:flex;"><span>  messages<span style="color:#ff7b72;font-weight:bold">=</span>[
</span></span><span style="display:flex;"><span>    {<span style="color:#a5d6ff">&#34;role&#34;</span>: <span style="color:#a5d6ff">&#34;user&#34;</span>, <span style="color:#a5d6ff">&#34;content&#34;</span>: <span style="color:#a5d6ff">&#34;使用繁體中文閱讀，幫我改錯字、加標點符號，並分段使內容更通順：</span><span style="color:#79c0ff">\n</span><span style="color:#a5d6ff">&#34;</span><span style="color:#ff7b72;font-weight:bold">+</span>transcript}
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 印出整理後的文字</span>
</span></span><span style="display:flex;"><span>print(completion<span style="color:#ff7b72;font-weight:bold">.</span>choices[<span style="color:#a5d6ff">0</span>]<span style="color:#ff7b72;font-weight:bold">.</span>message<span style="color:#ff7b72;font-weight:bold">.</span>content)
</span></span></code></pre></div><p>STEP 1：安裝相關 Python 套件，<code>pip install pytube pydub openai</code></p>
<p>STEP 2：建立一個<code>youtube-summary.py</code>的檔案，貼上 ChatGPT 的程式。</p>
<p>STEP 3：在終端機輸入<code>python youtube-summary.py</code>，然後稍等一段時間&hellip;就會看到成果啦！</p>
<p><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-06.webp" width="1400" height="614" alt="導入 OpenAI 的 GPT API，提升逐字稿可讀性（圖 6）" loading="lazy" decoding="async"></p>
<p>表面上看起來整理得挺不錯，但仔細看會發現結尾突然斷掉了，這是為什麼呢？</p>
<p>這邊用 OpenAI 官方文件比較好說明，每個 GPT 模型都有自己的 <code>max_tokens</code>，我們選用的 <code>gpt-3.5-turbo</code> 最高上限是 4096。</p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-07.webp" width="1400" height="1231" alt="用 Python 搭配 OpenAI 的 GPT、Whisper API 取得 Youtube 影片摘要（圖 2）" loading="lazy" decoding="async">
  <figcaption><a href="https://platform.openai.com/docs/models/gpt-3.5-turbo">https://platform.openai.com/docs/models/gpt-3.5</a></figcaption>
</figure>

<p>所以截斷的原因就是我們的 prompt 太長了，這邊跟大家科普一下，所謂 prompt 長度就是我們傳入的逐字稿長度。</p>
<p>而中文跟英文計算 Token 的方式也不盡相同，如果使用英文，1000 個 tokens 大約等於 750 個單字；但如果使用中文，1000 個 tokens 大約只有 400 字。</p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-08.webp" width="1400" height="1132" alt="用 Python 搭配 OpenAI 的 GPT、Whisper API 取得 Youtube 影片摘要（圖 3）" loading="lazy" decoding="async">
  <figcaption><a href="https://platform.openai.com/tokenizer">https://platform.openai.com/tokenizer</a></figcaption>
</figure>

<p>上面是補充說明，讓我們回到原本的話題，我們要如何讓逐字稿完整的被整理，不要被截斷呢？</p>
<p>最直覺的做法就是將逐字稿「分段」傳送過去，4096 的 token 換算成中文大約 1600 字，我們保守一點，用「1200」的長度來做分割，下面是整理好的程式。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 切割音檔成多個小檔案</span>
</span></span><span style="display:flex;"><span>chunk_size <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">100</span> <span style="color:#ff7b72;font-weight:bold">*</span> <span style="color:#a5d6ff">1000</span>  <span style="color:#8b949e;font-style:italic"># 100 秒</span>
</span></span><span style="display:flex;"><span>chunks <span style="color:#ff7b72;font-weight:bold">=</span> [audio_file[i:i<span style="color:#ff7b72;font-weight:bold">+</span>chunk_size] <span style="color:#ff7b72">for</span> i <span style="color:#ff7b72;font-weight:bold">in</span> range(<span style="color:#a5d6ff">0</span>, len(audio_file), chunk_size)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 使用 OpenAI 的 Audio API 將每個小檔案轉成文字，然後合併在一起</span>
</span></span><span style="display:flex;"><span>openai<span style="color:#ff7b72;font-weight:bold">.</span>api_key <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_API_KEY&#34;</span>
</span></span><span style="display:flex;"><span>transcript <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">for</span> chunk <span style="color:#ff7b72;font-weight:bold">in</span> chunks:
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">with</span> chunk<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;temp.wav&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;wav&#34;</span>) <span style="color:#ff7b72">as</span> f:
</span></span><span style="display:flex;"><span>        result <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>Audio<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;whisper-1&#34;</span>, f)
</span></span><span style="display:flex;"><span>        transcript <span style="color:#ff7b72;font-weight:bold">+=</span> result[<span style="color:#a5d6ff">&#34;text&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 依照我們指定的長度分割字串</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">def</span> <span style="color:#d2a8ff;font-weight:bold">split_text</span>(text, max_length):
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> [text[i:i<span style="color:#ff7b72;font-weight:bold">+</span>max_length] <span style="color:#ff7b72">for</span> i <span style="color:#ff7b72;font-weight:bold">in</span> range(<span style="color:#a5d6ff">0</span>, len(text), max_length)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 整理逐字稿</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">def</span> <span style="color:#d2a8ff;font-weight:bold">process_text</span>(text):
</span></span><span style="display:flex;"><span>    response <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>ChatCompletion<span style="color:#ff7b72;font-weight:bold">.</span>create(
</span></span><span style="display:flex;"><span>        model<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;gpt-3.5-turbo&#34;</span>,
</span></span><span style="display:flex;"><span>        messages<span style="color:#ff7b72;font-weight:bold">=</span>[
</span></span><span style="display:flex;"><span>            {<span style="color:#a5d6ff">&#34;role&#34;</span>: <span style="color:#a5d6ff">&#34;system&#34;</span>, <span style="color:#a5d6ff">&#34;content&#34;</span>: <span style="color:#a5d6ff">&#34;You are a helpful assistant.&#34;</span>},
</span></span><span style="display:flex;"><span>            {<span style="color:#a5d6ff">&#34;role&#34;</span>: <span style="color:#a5d6ff">&#34;user&#34;</span>, <span style="color:#a5d6ff">&#34;content&#34;</span>: <span style="color:#a5d6ff">&#34;使用繁體中文閱讀，幫我改錯字、加標點符號，並分段使內容更通順：</span><span style="color:#79c0ff">\n</span><span style="color:#a5d6ff">&#34;</span><span style="color:#ff7b72;font-weight:bold">+</span>text}
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> response<span style="color:#ff7b72;font-weight:bold">.</span>choices[<span style="color:#a5d6ff">0</span>]<span style="color:#ff7b72;font-weight:bold">.</span>message<span style="color:#ff7b72;font-weight:bold">.</span>content
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 處理長字串</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">def</span> <span style="color:#d2a8ff;font-weight:bold">process_long_text</span>(long_text):
</span></span><span style="display:flex;"><span>    text_list <span style="color:#ff7b72;font-weight:bold">=</span> split_text(long_text, <span style="color:#a5d6ff">1200</span>)
</span></span><span style="display:flex;"><span>    processed_text_list <span style="color:#ff7b72;font-weight:bold">=</span> [process_text(text) <span style="color:#ff7b72">for</span> text <span style="color:#ff7b72;font-weight:bold">in</span> text_list]
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> <span style="color:#a5d6ff">&#34;&#34;</span><span style="color:#ff7b72;font-weight:bold">.</span>join(processed_text_list)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 呼叫分段處理函式</span>
</span></span><span style="display:flex;"><span>processed_transcript <span style="color:#ff7b72;font-weight:bold">=</span> process_long_text(transcript)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 印出處理後的逐字稿</span>
</span></span><span style="display:flex;"><span>print(processed_transcript)
</span></span></code></pre></div><p>在終端機輸入<code>python youtube-summary.py</code>，就會看到被分段，並加上標點符號的成果啦！</p>
<p><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-09.webp" width="1400" height="639" alt="導入 OpenAI 的 GPT API，提升逐字稿可讀性（圖 9）" loading="lazy" decoding="async"></p>
<blockquote>
<p>關於字串分割的方式，筆者是向 ChatGPT 詢問：「我逐字稿的字數可能超過 1 萬字，而這個 api 最多只能讀 1200 字，請問我要如何改寫？」改編而來的；儘管 ChatGPT 面對新套件力有不逮，但基礎的問題還是可以順利回答。</p>
</blockquote>
<hr>
<h2 id="取得逐字稿摘要轉成-txt-格式">取得逐字稿摘要，轉成 txt 格式<a class="h-anchor" href="#%e5%8f%96%e5%be%97%e9%80%90%e5%ad%97%e7%a8%bf%e6%91%98%e8%a6%81%e8%bd%89%e6%88%90-txt-%e6%a0%bc%e5%bc%8f" aria-label="這個段落的連結"></a></h2>
<p>基本上下面的程式就是筆者自己改造的了，我做了兩件事：</p>
<ol>
<li>在 <code>process_long_text</code> 函式增加了一個 <code>type</code> 的參數，裡面可以放置不同類型的 prompt（ex：整理逐字稿、摘要）。</li>
<li>將整理好的文字寫入 txt 檔案。</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 切割音檔成多個小檔案</span>
</span></span><span style="display:flex;"><span>chunk_size <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">100</span> <span style="color:#ff7b72;font-weight:bold">*</span> <span style="color:#a5d6ff">1000</span>  <span style="color:#8b949e;font-style:italic"># 100 秒</span>
</span></span><span style="display:flex;"><span>chunks <span style="color:#ff7b72;font-weight:bold">=</span> [audio_file[i:i<span style="color:#ff7b72;font-weight:bold">+</span>chunk_size]
</span></span><span style="display:flex;"><span>          <span style="color:#ff7b72">for</span> i <span style="color:#ff7b72;font-weight:bold">in</span> range(<span style="color:#a5d6ff">0</span>, len(audio_file), chunk_size)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 使用 OpenAI 的 Audio API 將每個小檔案轉成文字，然後合併在一起</span>
</span></span><span style="display:flex;"><span>openai<span style="color:#ff7b72;font-weight:bold">.</span>api_key <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_API_KEY&#34;</span>
</span></span><span style="display:flex;"><span>transcript <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">for</span> chunk <span style="color:#ff7b72;font-weight:bold">in</span> chunks:
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">with</span> chunk<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;temp.wav&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;wav&#34;</span>) <span style="color:#ff7b72">as</span> f:
</span></span><span style="display:flex;"><span>        result <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>Audio<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;whisper-1&#34;</span>, f)
</span></span><span style="display:flex;"><span>        transcript <span style="color:#ff7b72;font-weight:bold">+=</span> result[<span style="color:#a5d6ff">&#34;text&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 依照我們指定的長度分割字串</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">def</span> <span style="color:#d2a8ff;font-weight:bold">split_text</span>(text, max_length):
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> [text[i:i<span style="color:#ff7b72;font-weight:bold">+</span>max_length] <span style="color:#ff7b72">for</span> i <span style="color:#ff7b72;font-weight:bold">in</span> range(<span style="color:#a5d6ff">0</span>, len(text), max_length)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 依照 type 處理文字</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">def</span> <span style="color:#d2a8ff;font-weight:bold">process_text</span>(text, type):
</span></span><span style="display:flex;"><span>    response <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>ChatCompletion<span style="color:#ff7b72;font-weight:bold">.</span>create(
</span></span><span style="display:flex;"><span>        model<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;gpt-3.5-turbo&#34;</span>,
</span></span><span style="display:flex;"><span>        messages<span style="color:#ff7b72;font-weight:bold">=</span>[
</span></span><span style="display:flex;"><span>            {<span style="color:#a5d6ff">&#34;role&#34;</span>: <span style="color:#a5d6ff">&#34;system&#34;</span>, <span style="color:#a5d6ff">&#34;content&#34;</span>: <span style="color:#a5d6ff">&#34;You are a helpful assistant.&#34;</span>},
</span></span><span style="display:flex;"><span>            {<span style="color:#a5d6ff">&#34;role&#34;</span>: <span style="color:#a5d6ff">&#34;user&#34;</span>, <span style="color:#a5d6ff">&#34;content&#34;</span>: type <span style="color:#ff7b72;font-weight:bold">+</span> text}
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> response<span style="color:#ff7b72;font-weight:bold">.</span>choices[<span style="color:#a5d6ff">0</span>]<span style="color:#ff7b72;font-weight:bold">.</span>message<span style="color:#ff7b72;font-weight:bold">.</span>content
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 處理長字串</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">def</span> <span style="color:#d2a8ff;font-weight:bold">process_long_text</span>(long_text, type):
</span></span><span style="display:flex;"><span>    text_list <span style="color:#ff7b72;font-weight:bold">=</span> split_text(long_text, <span style="color:#a5d6ff">1200</span>)
</span></span><span style="display:flex;"><span>    processed_text_list <span style="color:#ff7b72;font-weight:bold">=</span> [process_text(text, type) <span style="color:#ff7b72">for</span> text <span style="color:#ff7b72;font-weight:bold">in</span> text_list]
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> <span style="color:#a5d6ff">&#34;&#34;</span><span style="color:#ff7b72;font-weight:bold">.</span>join(processed_text_list)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 呼叫分段處理函式</span>
</span></span><span style="display:flex;"><span>processed_transcript <span style="color:#ff7b72;font-weight:bold">=</span> process_long_text(transcript, <span style="color:#a5d6ff">&#34;使用繁體中文閱讀，幫我改錯字、加標點符號，並分段使內容更通順：</span><span style="color:#79c0ff">\n</span><span style="color:#a5d6ff">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 呼叫取得摘要函式</span>
</span></span><span style="display:flex;"><span>processed_summary <span style="color:#ff7b72;font-weight:bold">=</span> process_long_text(processed_transcript, <span style="color:#a5d6ff">&#34;閱讀以下文字，用「-」作為前綴條列出重點，用「繁體中文」呈現：</span><span style="color:#79c0ff">\n</span><span style="color:#a5d6ff">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">with</span> open(<span style="color:#a5d6ff">&#34;path/to/save/directory/text.txt&#34;</span>, <span style="color:#a5d6ff">&#34;w&#34;</span>) <span style="color:#ff7b72">as</span> file:
</span></span><span style="display:flex;"><span>    file<span style="color:#ff7b72;font-weight:bold">.</span>write(<span style="color:#a5d6ff">&#34;摘要：</span><span style="color:#79c0ff">\n</span><span style="color:#a5d6ff">&#34;</span> <span style="color:#ff7b72;font-weight:bold">+</span> processed_summary <span style="color:#ff7b72;font-weight:bold">+</span> <span style="color:#a5d6ff">&#34;</span><span style="color:#79c0ff">\n\n\n</span><span style="color:#a5d6ff">逐字稿：</span><span style="color:#79c0ff">\n</span><span style="color:#a5d6ff">&#34;</span> <span style="color:#ff7b72;font-weight:bold">+</span> processed_transcript)
</span></span></code></pre></div><p>在終端機輸入<code>python youtube-summary.py</code>，就會看到「Youtube 摘要、整理過的逐字稿」被寫入 txt 檔案中啦！</p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-10.webp" width="1400" height="1042" alt="讀者可依照自己的需求再做優化" loading="lazy" decoding="async">
  <figcaption>讀者可依照自己的需求再做優化</figcaption>
</figure>

<hr>
<h2 id="筆者想說的話">筆者想說的話<a class="h-anchor" href="#%e7%ad%86%e8%80%85%e6%83%b3%e8%aa%aa%e7%9a%84%e8%a9%b1" aria-label="這個段落的連結"></a></h2>
<p>不知道有多少人會把文章看完，但其實這篇文章我寫得很沮喪。</p>
<p>程式的部分我花不到 1 小時就完工，但文章卻寫了 4 個多小時，我不停在思考怎麼樣的呈現方式對讀者來說是有幫助的。</p>
<p>最終我選擇了上面的呈現方式，任何工具都有不完美的地方，沒必要所有事情都依賴 ChatGPT。</p>
<p>以這篇文章完成的功能來說，ChatGPT 的幫助如下：</p>
<ol>
<li>提供字串分割的函式</li>
<li>寫入 txt 檔案的方式</li>
</ol>
<p>其他部分基本上都是筆者自己改寫的，並不是說 ChatGPT 絕對辦不到，只是想表達工具用在對的地方才會有最大效益（ex：基礎程式、簡單除錯、最小可執行程式），我也不想只呈現完美的路徑。</p>
<p>最後再聊聊自己為什麼會寫這個 Side Project 吧。</p>
<p>我這個人喜歡閱讀文章大過看影片，因為我可以在文章中快速找到自己需要的重點，而觀看影片很難讓我做到這件事。</p>
<p>如果看影片是為了娛樂，那我會享受這個過程；但有時看影片是為了吸收知識，那這樣的效率對我來說就太慢了，所以我就做了這個小工具，提升自己吸收知識的效率。</p>
<blockquote>
<p>我喜歡依照自己的「節奏」來吸收資訊，而閱讀滿足了這點。</p>
</blockquote>
<hr>
<a class="linkcard" href="https://deanlin.net/categories/ai/">
  <span class="lc-body">
    <span class="lc-title">AI 實戰</span>
    <span class="lc-desc">實測生成式 AI 工具、Vibe Coding 與自動化流程的第一手心得，把 AI 變成每天都用得上的即戰力。</span>
    <span class="lc-site"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>林鼎淵 Dean Lin</span>
  </span>
</a>

<p><strong>想將 AI 導入自己的職場與生活嗎？歡迎<a href="https://www.books.com.tw/products/0011004216">購買筆者出版的新書</a></strong>，幫助您<strong>在 AI 的浪潮中站穩腳步，並在未來的職場競爭中佔據優勢！</strong></p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/images/youtube-summary-gpt-whisper-api-11.webp" width="1400" height="319" alt="林鼎淵著作《ChatGPT 與 AI 繪圖效率大師（新增 Copilot、Gamma、Runway、Suno）》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.books.com.tw/products/0011004216">https://www.books.com.tw/products/0011004216</a></figcaption>
</figure>

]]></content:encoded>
    </item>
    <item>
      <title>在 Local 導入 Whisper 套件，用 Python 免費將 Youtube 影片轉換成逐字稿！</title>
      <link>https://deanlin.net/blog/202304/local-whisper-youtube-transcript/</link>
      <pubDate>Sat, 01 Apr 2023 12:26:52 +0800</pubDate>
      <guid>https://deanlin.net/blog/202304/local-whisper-youtube-transcript/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>AI 實戰</category>
      <description>如果每次轉逐字稿都使用線上的 Whisper API 會快速消耗 OpenAI 的 Token，要是時常有轉長影片的需求，那可能得花不少錢在上面。 所以這篇文章筆者要向大家介紹如何在 Local 環境導入 Whisper 套件的方案，免費將 Youtube 影片轉換成逐字稿！</description>
      <media:content url="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-og_hu_69d6a28f62c3f0cd.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<p>如果每次轉逐字稿都使用線上的 Whisper API 會快速消耗 OpenAI 的 Token，要是時常有轉長影片的需求，那可能得花不少錢在上面（雖然他真的很方便）。</p>
<p>所以這篇文章筆者要向大家介紹如何在 Local 環境導入 Whisper 套件的方案，免費將 Youtube 影片轉換成逐字稿！</p>
<p><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-01.webp" width="1291" height="711" alt="在 Local 導入 Whisper 套件，用 Python 免費將 Youtube 影片轉換成逐字稿！（圖 1）" fetchpriority="high" decoding="async"></p>
<blockquote class="pullquote"><p>提醒大家，不要未經授權下載有版權保護的影片喔！</p>
</blockquote>
<blockquote>
<p><strong>小提醒</strong>：雖然原則上按照步驟就能順利完成，但每個人的電腦環境會有些許差異，遇到特殊狀況時，請自行排除（或是問 ChatGPT）。</p>
</blockquote>
<h2 id="觀看-whisper-官方文件">觀看 Whisper 官方文件<a class="h-anchor" href="#%e8%a7%80%e7%9c%8b-whisper-%e5%ae%98%e6%96%b9%e6%96%87%e4%bb%b6" aria-label="這個段落的連結"></a></h2>
<p>GitHub 官網：<a href="https://github.com/openai/whisper">https://github.com/openai/whisper</a></p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-02.webp" width="1400" height="1061" alt="有興趣的朋友可以看圖片，來了解這款套件的訓練方式，這邊筆者就不再贅述。" loading="lazy" decoding="async">
  <figcaption>有興趣的朋友可以看圖片，來了解這款套件的訓練方式，這邊筆者就不再贅述。</figcaption>
</figure>

<hr>
<h2 id="安裝-whisper-套件">安裝 Whisper 套件<a class="h-anchor" href="#%e5%ae%89%e8%a3%9d-whisper-%e5%a5%97%e4%bb%b6" aria-label="這個段落的連結"></a></h2>
<p><strong>STEP 1</strong>：首先要特別注意的，就是目前這款套件是使用「Python 3.9.9」的版本，如果你安裝的是最新版的 Python，那後續連基礎的安裝就會失敗。</p>
<p>安裝 Python 3.9 版本：<code>brew install <a href="mailto:python@3.9">python@3.9</a></code></p>
<p><strong>STEP 2</strong>：如果你在 local 環境已經安裝了其他版本的 Python，就需要切換到 3.9 的版本才能夠順利執行後續安裝，建議直接改 alias 比較快。</p>
<pre tabindex="0"><code>vi ~/.zshrc
alias python=&#39;python3.9&#39;
alias pip=&#39;pip3.9
</code></pre><p><strong>STEP 3</strong>：前面兩個步驟完成後，接下來安裝「通常」就會順利很多。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pip install torch torchvision torchaudio
</span></span><span style="display:flex;"><span>pip install ffmpeg-python
</span></span><span style="display:flex;"><span>pip install -U openai-whisper
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># windows (https://chocolatey.org/)可使用 choco install ffmpeg</span>
</span></span><span style="display:flex;"><span>brew install ffmpeg
</span></span><span style="display:flex;"><span>pip install setuptools-rust
</span></span></code></pre></div><blockquote>
<p>如果想了解每個套件負責的任務是什麼，可以參考官網：<a href="https://github.com/openai/whisper#setup">https://github.com/openai/whisper#setup</a></p>
</blockquote>
<p><strong>STEP 4</strong>：確認是否安裝成功。</p>
<p>在終端機輸入指令：<code>whisper &ndash;help</code>，如果出現下面的畫面就代表你安裝成功嚕！</p>
<p><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-03.webp" width="1400" height="640" alt="安裝 Whisper 套件（圖 3）" loading="lazy" decoding="async"></p>
<hr>
<h2 id="用-whisper-套件將-youtube-影片轉換成逐字稿">用 Whisper 套件將 Youtube 影片轉換成逐字稿<a class="h-anchor" href="#%e7%94%a8-whisper-%e5%a5%97%e4%bb%b6%e5%b0%87-youtube-%e5%bd%b1%e7%89%87%e8%bd%89%e6%8f%9b%e6%88%90%e9%80%90%e5%ad%97%e7%a8%bf" aria-label="這個段落的連結"></a></h2>
<p>筆者在<a href="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/">前面的文章</a>，已經完成將 Youtube 影片轉換成音檔的程式，接下來我們可以請 ChatGPT 幫我們做程式組合的任務。</p>
<blockquote>
<p>請自行安裝 pytube、pydub 的套件。</p>
</blockquote>
<p>😀：「下面是我用 Python 寫的 Youtube 影片轉成音檔的程式，我想要在這個基礎上擴充功能，我在後續的對話中會提出自己的需求，請問你可以幫忙嗎？</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 檢查音檔是否可以正常解碼</span>
</span></span><span style="display:flex;"><span>print(audio_file)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 將音檔轉換為 MP3 格式</span>
</span></span><span style="display:flex;"><span>mp3_file <span style="color:#ff7b72;font-weight:bold">=</span> audio_file<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.mp3&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;mp3&#34;</span>)
</span></span></code></pre></div><p><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-04.webp" width="1007" height="336" alt="用 Whisper 套件將 Youtube 影片轉換成逐字稿（圖 4）" loading="lazy" decoding="async"></p>
<p>😀：「我找到了一個可以將 mp3 檔案轉成文字檔的套件，官方範例如下，我要如何將他與我現在的程式結合呢？</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">whisper</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>model <span style="color:#ff7b72;font-weight:bold">=</span> whisper<span style="color:#ff7b72;font-weight:bold">.</span>load_model(<span style="color:#a5d6ff">&#34;base&#34;</span>)
</span></span><span style="display:flex;"><span>result <span style="color:#ff7b72;font-weight:bold">=</span> model<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;audio.mp3&#34;</span>)
</span></span><span style="display:flex;"><span>print(result[<span style="color:#a5d6ff">&#34;text&#34;</span>])
</span></span></code></pre></div><p><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-05.webp" width="1007" height="806" alt="用 Whisper 套件將 Youtube 影片轉換成逐字稿（圖 5）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-06.webp" width="1007" height="734" alt="用 Whisper 套件將 Youtube 影片轉換成逐字稿（圖 6）" loading="lazy" decoding="async"></p>
<p>我們在前面已經完成相關的套件安裝了，接下來直接嘗試看看 ChatGPT 組合後的程式是否靠譜。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">whisper</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 檢查音檔是否可以正常解碼</span>
</span></span><span style="display:flex;"><span>print(audio_file)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 將音檔轉換為 MP3 格式</span>
</span></span><span style="display:flex;"><span>mp3_file <span style="color:#ff7b72;font-weight:bold">=</span> audio_file<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.mp3&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;mp3&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取 MP3 檔案，轉成文字檔案</span>
</span></span><span style="display:flex;"><span>model <span style="color:#ff7b72;font-weight:bold">=</span> whisper<span style="color:#ff7b72;font-weight:bold">.</span>load_model(<span style="color:#a5d6ff">&#34;base&#34;</span>)
</span></span><span style="display:flex;"><span>result <span style="color:#ff7b72;font-weight:bold">=</span> model<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.mp3&#34;</span>)
</span></span><span style="display:flex;"><span>print(result[<span style="color:#a5d6ff">&#34;text&#34;</span>])
</span></span></code></pre></div><p><strong>SETP 1</strong>：建立一個<code>youtube-local-whisper.py</code>的檔案，貼上 ChatGPT 的程式。</p>
<p><strong>SETP 2</strong>：在終端機輸入<code>python youtube-local-whisper.py</code>，然後稍等一段時間&hellip;就可以見證奇蹟啦！</p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-07.webp" width="1400" height="840" alt="儘管有成功轉換逐字稿，但這個品質真的有點悲劇。" loading="lazy" decoding="async">
  <figcaption>儘管有成功轉換逐字稿，但這個品質真的有點悲劇。</figcaption>
</figure>

<hr>
<h2 id="提升轉出的逐字稿品質">提升轉出的逐字稿品質<a class="h-anchor" href="#%e6%8f%90%e5%8d%87%e8%bd%89%e5%87%ba%e7%9a%84%e9%80%90%e5%ad%97%e7%a8%bf%e5%93%81%e8%b3%aa" aria-label="這個段落的連結"></a></h2>
<p>在程式中，預設的 model 是 base 模型，實際上他有提供這些模型供我們選擇：「tiny/base/small/medium/large」</p>
<p>不過越往上，對電腦的需求越高，花費時間越多，我們可以先看一下官方提供的對照表：</p>
<p><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-08.webp" width="1400" height="391" alt="提升轉出的逐字稿品質（圖 8）" loading="lazy" decoding="async"></p>
<p>除了 model 的選擇外，另一個是「語言」，如果一開始有設定好也能提升辨識的準確度（ex：中文是「zh」）。</p>
<blockquote>
<p>有興趣的朋友可以看一下套件目前提供的語言列表：<a href="https://github.com/openai/whisper/blob/main/whisper/tokenizer.py">https://github.com/openai/whisper/blob/main/whisper/tokenizer.py</a></p>
</blockquote>
<p>下面是筆者將語言調整成「zh」，並選擇「medium」這個 Model 優化的程式（除非你電腦性能超級優秀，否則選擇 large 會等到天荒地老）：</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">whisper</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 檢查音檔是否可以正常解碼</span>
</span></span><span style="display:flex;"><span>print(audio_file)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 將音檔轉換為 MP3 格式</span>
</span></span><span style="display:flex;"><span>mp3_file <span style="color:#ff7b72;font-weight:bold">=</span> audio_file<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.mp3&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;mp3&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取 MP3 檔案，轉成文字檔案</span>
</span></span><span style="display:flex;"><span>model <span style="color:#ff7b72;font-weight:bold">=</span> whisper<span style="color:#ff7b72;font-weight:bold">.</span>load_model(<span style="color:#a5d6ff">&#34;medium&#34;</span>)
</span></span><span style="display:flex;"><span>result <span style="color:#ff7b72;font-weight:bold">=</span> model<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.mp3&#34;</span>, language<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#39;zh&#39;</span>)
</span></span><span style="display:flex;"><span>print(result[<span style="color:#a5d6ff">&#34;text&#34;</span>])
</span></span></code></pre></div><p>這次輸出的結果總算是比較接近預期的了（真的要等一段時間喔…）。</p>
<p><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-09.webp" width="1400" height="868" alt="提升轉出的逐字稿品質（圖 9）" loading="lazy" decoding="async"></p>
<p>如果覺得看起來眼花，那就交給 ChatGPT 幫你整理一下吧！</p>
<p>😀：「幫我改錯字、分段、加標點符號，讓內容更通順：[逐字稿]」</p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-10.webp" width="1021" height="709" alt="大家可以發現裡面的文字不是百分百正確，品質還是需要自己把關的喔！" loading="lazy" decoding="async">
  <figcaption>大家可以發現裡面的文字不是百分百正確，品質還是需要自己把關的喔！</figcaption>
</figure>

<hr>
<h2 id="結論優化還是需要一定的專業水平">結論：優化還是需要一定的專業水平<a class="h-anchor" href="#%e7%b5%90%e8%ab%96%e5%84%aa%e5%8c%96%e9%82%84%e6%98%af%e9%9c%80%e8%a6%81%e4%b8%80%e5%ae%9a%e7%9a%84%e5%b0%88%e6%a5%ad%e6%b0%b4%e5%b9%b3" aria-label="這個段落的連結"></a></h2>
<p>如果是一個 0 基礎的人，我會更建議使用筆者的<a href="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/">另外一篇文章</a>，來實作 Youtube 轉逐字稿的功能。</p>
<p>因為在 Local 環境導入 Whisper 真的還是有一些技術門檻，光是環境設定的部分，就可能讓沒經驗的人經歷「困惑 ➝ 絕望 ➝ 投降」的 3 個階段；不過，如果能順利設定完成，那將給自己帶來巨大的成就感。</p>
<p>儘管初步的程式，我們可以靠 ChatGPT 幫我們組合出來；但因為 Whisper 畢竟是一款新的套件，如果想要對他優化，還是需要具備閱讀技術文件的能力。</p>
<p>有了 AI 輔助，工程師就能把更多的精力放在優化而非基礎建設上，相信在不久的將來，M 型化會越來越明顯。</p>
<hr>
<a class="linkcard" href="https://deanlin.net/categories/ai/">
  <span class="lc-body">
    <span class="lc-title">AI 實戰</span>
    <span class="lc-desc">實測生成式 AI 工具、Vibe Coding 與自動化流程的第一手心得，把 AI 變成每天都用得上的即戰力。</span>
    <span class="lc-site"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>林鼎淵 Dean Lin</span>
  </span>
</a>

<p><strong>想將 AI 導入自己的職場與生活嗎？歡迎<a href="https://www.books.com.tw/products/0011004216">購買筆者出版的新書</a></strong>，幫助您<strong>在 AI 的浪潮中站穩腳步，並在未來的職場競爭中佔據優勢！</strong></p>
<figure class="figure"><img src="https://deanlin.net/blog/202304/local-whisper-youtube-transcript/images/local-whisper-youtube-transcript-11.webp" width="1400" height="319" alt="林鼎淵著作《ChatGPT 與 AI 繪圖效率大師（新增 Copilot、Gamma、Runway、Suno）》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.books.com.tw/products/0011004216">https://www.books.com.tw/products/0011004216</a></figcaption>
</figure>

]]></content:encoded>
    </item>
    <item>
      <title>進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）</title>
      <link>https://deanlin.net/blog/202303/python-youtube-transcript-whisper/</link>
      <pubDate>Fri, 31 Mar 2023 13:50:25 +0800</pubDate>
      <guid>https://deanlin.net/blog/202303/python-youtube-transcript-whisper/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>AI 實戰</category>
      <description>上一篇文章中，筆者靠 ChatGPT 成功將 Youtube 影片轉換成音檔（mp3），在這篇文章中，我會分享如何用 OpenAI 提供的 whisper api 將 音檔轉成逐字稿。</description>
      <media:content url="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-og_hu_4c10fd0e7b3aa439.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<p><a href="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/">上一篇文章中</a>，筆者靠 ChatGPT 成功將 Youtube 影片轉換成音檔（mp3），在這篇文章中，我會分享如何用 OpenAI 提供的 whisper api 將 音檔轉成逐字稿。</p>
<blockquote>
<p>如果沒有程式基礎的朋友，建議先從<a href="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/">上一篇文章</a>開始閱讀。</p>
</blockquote>
<p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-01.webp" width="1289" height="717" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 1）" fetchpriority="high" decoding="async"></p>
<blockquote class="pullquote"><p><em>提醒大家，不要未經授權下載有版權保護的影片喔！</em></p>
</blockquote>
<p>目前的 ChatGPT 資料截止於 2021 年 9 月，如果用到最近才新增的技術，我們還是要先到官網查看文件。</p>
<p>OpenAI 技術文件：<a href="https://platform.openai.com/docs/guides/speech-to-text">https://platform.openai.com/docs/guides/speech-to-text</a></p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-02.webp" width="1400" height="906" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 2）" loading="lazy" decoding="async"></p>
<p>儘管 ChatGPT 不知道未來世界的資料，但我們還是可以請他幫我們將程式重組。</p>
<p>😀：「下面是我用 Python 寫的 Youtube 影片轉成音檔的程式，我想要在這個基礎上擴充功能，我在後續的對話中會提出自己的需求，請問你可以幫忙嗎？</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 檢查音檔是否可以正常解碼</span>
</span></span><span style="display:flex;"><span>print(audio_file)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 將音檔轉換為 MP3 格式</span>
</span></span><span style="display:flex;"><span>mp3_file <span style="color:#ff7b72;font-weight:bold">=</span> audio_file<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.mp3&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;mp3&#34;</span>)
</span></span></code></pre></div><p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-03.webp" width="1012" height="445" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 3）" loading="lazy" decoding="async"></p>
<p>😀：「我找到了一個可以將 mp3 檔案轉成文字檔的套件，官方範例如下，我要如何將他與我現在的程式結合呢？</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>audio_file<span style="color:#ff7b72;font-weight:bold">=</span> open(<span style="color:#a5d6ff">&#34;/path/to/file/audio.mp3&#34;</span>, <span style="color:#a5d6ff">&#34;rb&#34;</span>)
</span></span><span style="display:flex;"><span>transcript <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>Audio<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;whisper-1&#34;</span>, audio_file)
</span></span></code></pre></div><p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-04.webp" width="1012" height="728" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 4）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-05.webp" width="1012" height="445" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 5）" loading="lazy" decoding="async"></p>
<p>有了 ChatGPT 的提示後，我們可以按照下面的步驟操作。</p>
<p><strong>SETP 1</strong>：安裝新套件：<code>pip3 install openai</code>。</p>
<blockquote>
<p>如果上一篇文章沒有安裝到，請記得順便安裝不然會有錯誤訊息喔：<code>pip install pydub pytube</code></p>
</blockquote>
<p><strong>SETP 2</strong>：建立一個檔案<code>youtube-to-text.py</code>，然後貼上 ChatGPT 提供的程式。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 將音檔轉換為 WAV 格式</span>
</span></span><span style="display:flex;"><span>wav_file <span style="color:#ff7b72;font-weight:bold">=</span> audio_file<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.wav&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;wav&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 使用 OpenAI 的 Audio API 將音檔轉成文字</span>
</span></span><span style="display:flex;"><span>openai<span style="color:#ff7b72;font-weight:bold">.</span>api_key <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_API_KEY&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">with</span> open(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.wav&#34;</span>, <span style="color:#a5d6ff">&#34;rb&#34;</span>) <span style="color:#ff7b72">as</span> f:
</span></span><span style="display:flex;"><span>    transcript <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>Audio<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;whisper-1&#34;</span>, f)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 印出轉換後的文字</span>
</span></span><span style="display:flex;"><span>print(transcript)
</span></span></code></pre></div><blockquote>
<p>我們原本是將 Youtube 轉換成 mp3 檔，而這次 ChatGPT 改寫的過程中，把它轉換成了 wav 檔；並且對我們提供的範例程式做了一定程度的改寫（ex：告訴我們要自己填入”YOUR_API_KEY”）。</p>
</blockquote>
<p><strong>SETP 3</strong>：請先去 <a href="https://platform.openai.com/account/api-keys">https://platform.openai.com/account/api-keys</a> 申請自己的 API Key，將 YOUR_API_KEY 替換成自己的。</p>
<blockquote>
<p><strong>小提醒：</strong>將 API Key 放入環境變數的作法更好，不過這篇文章以 Demo 目的為主，讀者切記不要把自己的 API Key 洩露出去了。</p>
</blockquote>
<p><strong>SETP 4</strong>：輸入 <code>python youtube-to-text.py</code> 執行程式，結果遇到了錯誤如下：</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-06.webp" width="1400" height="574" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 6）" loading="lazy" decoding="async"></p>
<p>看不懂錯誤訊息沒關係，直接貼到 ChatGPT。</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-07.webp" width="1001" height="746" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 7）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-08.webp" width="860" height="756" alt="進階應用！詢問 ChatGPT 如何用 Python 將 Youtube 影片轉換成逐字稿（OpenAI 的 whisper）（圖 8）" loading="lazy" decoding="async"></p>
<p>原來是檔案大小的問題，這邊筆者將 10 秒的時間拉長到 100 秒，避免聲音切割過度。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">import</span> <span style="color:#ff7b72">openai</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 切割音檔成多個小檔案</span>
</span></span><span style="display:flex;"><span>chunk_size <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">100</span> <span style="color:#ff7b72;font-weight:bold">*</span> <span style="color:#a5d6ff">1000</span>  <span style="color:#8b949e;font-style:italic"># 100 秒</span>
</span></span><span style="display:flex;"><span>chunks <span style="color:#ff7b72;font-weight:bold">=</span> [audio_file[i:i<span style="color:#ff7b72;font-weight:bold">+</span>chunk_size] <span style="color:#ff7b72">for</span> i <span style="color:#ff7b72;font-weight:bold">in</span> range(<span style="color:#a5d6ff">0</span>, len(audio_file), chunk_size)]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 使用 OpenAI 的 Audio API 將每個小檔案轉成文字，然後合併在一起</span>
</span></span><span style="display:flex;"><span>openai<span style="color:#ff7b72;font-weight:bold">.</span>api_key <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_API_KEY&#34;</span>
</span></span><span style="display:flex;"><span>transcript <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">for</span> chunk <span style="color:#ff7b72;font-weight:bold">in</span> chunks:
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">with</span> chunk<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;temp.wav&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;wav&#34;</span>) <span style="color:#ff7b72">as</span> f:
</span></span><span style="display:flex;"><span>        result <span style="color:#ff7b72;font-weight:bold">=</span> openai<span style="color:#ff7b72;font-weight:bold">.</span>Audio<span style="color:#ff7b72;font-weight:bold">.</span>transcribe(<span style="color:#a5d6ff">&#34;whisper-1&#34;</span>, f)
</span></span><span style="display:flex;"><span>        transcript <span style="color:#ff7b72;font-weight:bold">+=</span> result[<span style="color:#a5d6ff">&#34;text&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 印出轉換後的文字</span>
</span></span><span style="display:flex;"><span>print(transcript)
</span></span></code></pre></div><p>再輸入一次 <code>python youtube-to-text.py</code> 執行程式，接著就順利取得逐字稿啦！！！！</p>
<figure class="figure"><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-09.webp" width="1400" height="795" alt="大家可以發現裡面的文字不是百分百正確，品質還是需要自己把關的喔！" loading="lazy" decoding="async">
  <figcaption>大家可以發現裡面的文字不是百分百正確，品質還是需要自己把關的喔！</figcaption>
</figure>

<h2 id="結論要懂得組合應用">結論：要懂得組合應用<a class="h-anchor" href="#%e7%b5%90%e8%ab%96%e8%a6%81%e6%87%82%e5%be%97%e7%b5%84%e5%90%88%e6%87%89%e7%94%a8" aria-label="這個段落的連結"></a></h2>
<p>相比於上一篇，這篇文章的門檻比較高，像是多了：</p>
<ol>
<li>前往 OpenAI 官網，取得所需技術文件</li>
<li>需要一定的英文閱讀能力（雖然你也可以請 ChatGPT 幫你翻譯）</li>
<li>讓原有程式基礎上，疊加新應用的提問技巧</li>
</ol>
<p>不過儘管我們取得了逐字稿，但這份逐字稿真的有點醜，閱讀起來有點困難。</p>
<p>這邊我們可以直接把他丟到 ChatGPT，請他幫忙分段落、整理摘要。</p>
<p>😀：「幫我改錯字、分段、加標點符號，讓內容更通順：<code>[逐字稿]</code>」</p>
<figure class="figure"><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-10.webp" width="1014" height="711" alt="大家可以發現裡面的文字不是百分百正確，品質還是需要自己把關的喔！" loading="lazy" decoding="async">
  <figcaption>大家可以發現裡面的文字不是百分百正確，品質還是需要自己把關的喔！</figcaption>
</figure>

<p>😀：「幫我擷取 300 字摘要：<code>[逐字稿]</code>」</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-11.webp" width="1014" height="287" alt="結論：要懂得組合應用（圖 11）" loading="lazy" decoding="async"></p>
<blockquote>
<p>摘要的內容有點赤裸 😅，不過當年筆者參加比賽的確就是為了出書。</p>
</blockquote>
<p>不過手動貼到 ChatGPT 還是有點麻煩，<a href="https://deanlin.net/blog/202304/youtube-summary-gpt-whisper-api/">下一篇筆者就來分享如何透過 OpenAI 的 GPT-3.5 模型</a>，幫我們整理逐字稿內容吧！</p>
<hr>
<a class="linkcard" href="https://deanlin.net/categories/ai/">
  <span class="lc-body">
    <span class="lc-title">AI 實戰</span>
    <span class="lc-desc">實測生成式 AI 工具、Vibe Coding 與自動化流程的第一手心得，把 AI 變成每天都用得上的即戰力。</span>
    <span class="lc-site"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>林鼎淵 Dean Lin</span>
  </span>
</a>

<p><strong>想將 AI 導入自己的職場與生活嗎？歡迎<a href="https://www.books.com.tw/products/0011004216">購買筆者出版的新書</a></strong>，幫助您<strong>在 AI 的浪潮中站穩腳步，並在未來的職場競爭中佔據優勢！</strong></p>
<figure class="figure"><img src="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/images/python-youtube-transcript-whisper-12.webp" width="1400" height="319" alt="林鼎淵著作《ChatGPT 與 AI 繪圖效率大師（新增 Copilot、Gamma、Runway、Suno）》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.books.com.tw/products/0011004216">https://www.books.com.tw/products/0011004216</a></figcaption>
</figure>

]]></content:encoded>
    </item>
    <item>
      <title>0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）</title>
      <link>https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/</link>
      <pubDate>Wed, 29 Mar 2023 22:46:00 +0800</pubDate>
      <guid>https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>AI 實戰</category>
      <description>筆者真的嚇到了🫢，沒想到我真的做到一行程式碼都沒寫，以菜鳥的語氣跟 ChatGPT 對話，就能完成一個用 Python 將 Youtube 影片轉成音檔（mp3）的小專案。</description>
      <media:content url="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-og_hu_ebf6d4c0209bcab.jpg" medium="image" type="image/jpeg" width="1200" height="630" />
      <content:encoded><![CDATA[<p>筆者真的嚇到了🫢，沒想到我真的做到一行程式碼都沒寫，以菜鳥的語氣跟 ChatGPT 對話，就能完成一個用 Python 將 Youtube 影片轉成音檔（mp3）的小專案。</p>
<p>在這篇文章中，我附上與 ChatGPT 的完整對話，大家只要複製貼上就可以嘗試看看嚕！</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-01.webp" width="1139" height="626" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 1）" fetchpriority="high" decoding="async"></p>
<blockquote>
<p>Python 環境安裝的部分我就不贅述了，筆者使用的是 Python3；不過有設定 alias name，讓 python3/pip3 的指令對應 python/pip。</p>
</blockquote>
<p>😀：「我使用的程式語言是 Python，他有辦法抓取 Youtube 影片的音擋嗎？」</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-02.webp" width="886" height="692" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 2）" loading="lazy" decoding="async"></p>
<blockquote class="pullquote"><p>ChatGPT 這邊也有提醒大家，不要未經授權下載有版權保護的影片喔！</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=VIDEO_ID&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span></code></pre></div><p><strong>SETP 1</strong>：建立一個<code>youtube-test.py</code>的檔案，貼上 ChatGPT 的程式。</p>
<p><strong>SETP 2</strong>：如果要執行程式，請安裝套件：<code>pip install pytube</code>。</p>
<p><strong>SETP 3</strong>：將 url 替換成自己的：<a href="https://www.youtube.com/watch?v=IvOdTbIYZs4">https://www.youtube.com/watch?v=IvOdTbIYZs4</a></p>
<blockquote>
<p>這是筆者分享出書心得的影片。</p>
</blockquote>
<p><strong>SETP 4</strong>：在終端機輸入<code>python youtube-test.py</code>執行它，你會發現他自動建立了資料夾路徑，裡面存放著「audio」的檔案。</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-03.webp" width="584" height="388" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 3）" loading="lazy" decoding="async"></p>
<p>😀：「有順利在「path/to/save/directory」這個路徑下產生「audio」的檔案了，但他無法打開，這個真的是音擋嗎？」</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-04.webp" width="886" height="653" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 4）" loading="lazy" decoding="async"></p>
<blockquote>
<p>請安裝套件：<code>pip install pydub</code></p>
</blockquote>
<p>😀：「如何與上一段程式結合呢？」</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-05.webp" width="807" height="720" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 5）" loading="lazy" decoding="async"></p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>Copy code
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=VIDEO_ID&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 檢查音檔是否可以正常解碼</span>
</span></span><span style="display:flex;"><span>print(audio_file)
</span></span></code></pre></div><p>在終端機輸入<code>python youtube-test.py</code>，結果冒出一堆錯誤訊息。</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-06.webp" width="1400" height="612" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 6）" loading="lazy" decoding="async"></p>
<p>把錯誤的結果貼到 ChatGPT，他是會幫你解答的。</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-07.webp" width="995" height="425" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 7）" loading="lazy" decoding="async"></p>
<blockquote>
<p>若未安裝 homebrew 的朋友也可以詢問 ChatGPT 如何安裝。</p>
</blockquote>
<p>在終端機輸入<code>brew install ffmpeg</code>，之後等他安裝完成（頗久的&hellip;）</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-08.webp" width="1400" height="706" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 8）" loading="lazy" decoding="async"></p>
<p>再輸入一次<code>python youtube-test.py</code>，從終端機來看，天下太平了！</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-09.webp" width="1400" height="101" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 9）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-10.webp" width="882" height="681" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 10）" loading="lazy" decoding="async"></p>
<p>然後我們把 ChatGPT 的建議加入最後一行，讓他轉成 mp3 檔案。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pytube</span> <span style="color:#ff7b72">import</span> YouTube
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">from</span> <span style="color:#ff7b72">pydub</span> <span style="color:#ff7b72">import</span> AudioSegment
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 設定要下載的影片 URL</span>
</span></span><span style="display:flex;"><span>url <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;https://www.youtube.com/watch?v=IvOdTbIYZs4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 建立 YouTube 物件</span>
</span></span><span style="display:flex;"><span>yt <span style="color:#ff7b72;font-weight:bold">=</span> YouTube(url)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 取得影片的音軌</span>
</span></span><span style="display:flex;"><span>audio_stream <span style="color:#ff7b72;font-weight:bold">=</span> yt<span style="color:#ff7b72;font-weight:bold">.</span>streams<span style="color:#ff7b72;font-weight:bold">.</span>filter(only_audio<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#79c0ff">True</span>)<span style="color:#ff7b72;font-weight:bold">.</span>first()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 下載音軌到指定的路徑</span>
</span></span><span style="display:flex;"><span>audio_stream<span style="color:#ff7b72;font-weight:bold">.</span>download(output_path<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;path/to/save/directory&#34;</span>, filename<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 讀取下載下來的音檔</span>
</span></span><span style="display:flex;"><span>audio_file <span style="color:#ff7b72;font-weight:bold">=</span> AudioSegment<span style="color:#ff7b72;font-weight:bold">.</span>from_file(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 檢查音檔是否可以正常解碼</span>
</span></span><span style="display:flex;"><span>print(audio_file)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># 將音檔轉換為 MP3 格式</span>
</span></span><span style="display:flex;"><span>mp3_file <span style="color:#ff7b72;font-weight:bold">=</span> audio_file<span style="color:#ff7b72;font-weight:bold">.</span>export(<span style="color:#a5d6ff">&#34;path/to/save/directory/audio.mp3&#34;</span>, format<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">&#34;mp3&#34;</span>)
</span></span></code></pre></div><p>此時你在終端機執行<code>python youtube-test.py</code> 會有一種感動！這個 mp3 擋真的在播放 Youtube 影片的音檔了…太神了…</p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-11.webp" width="818" height="328" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 11）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-12.webp" width="1400" height="637" alt="0 基礎！讓 ChatGPT 手把手教你用 Python 將 Youtube 影片轉成音檔（mp3）（圖 12）" loading="lazy" decoding="async"></p>
<h2 id="結語讓不會程式的人更願意嘗試">結語：讓不會程式的人更願意嘗試<a class="h-anchor" href="#%e7%b5%90%e8%aa%9e%e8%ae%93%e4%b8%8d%e6%9c%83%e7%a8%8b%e5%bc%8f%e7%9a%84%e4%ba%ba%e6%9b%b4%e9%a1%98%e6%84%8f%e5%98%97%e8%a9%a6" aria-label="這個段落的連結"></a></h2>
<p>寫程式是一條非常艱辛的路，中間會遇到非常多的險阻與挫折。</p>
<p>就像上面展示的範例一樣，我們很難一次就得到正確的結果，但在發生錯誤時，過往會需要花費大量的時間除錯、找文件。</p>
<p>這些失敗的經歷會使人成長，但同時也會消耗熱情。</p>
<p>而 ChatGPT 的出現，很大程度地減緩了這塊的痛苦，讓我們更容易上手程式。</p>
<blockquote>
<p>不過這對程式教育產業來說，可說是巨大的衝擊，因為人們多了一個全新的選擇（而且還不賴）。</p>
<p>下一篇就來分享<a href="https://deanlin.net/blog/202303/python-youtube-transcript-whisper/">如何搭配 OpenAI 的 whisper api 將音檔（mp3）轉換成文字吧</a>！</p>
</blockquote>
<hr>
<a class="linkcard" href="https://deanlin.net/categories/ai/">
  <span class="lc-body">
    <span class="lc-title">AI 實戰</span>
    <span class="lc-desc">實測生成式 AI 工具、Vibe Coding 與自動化流程的第一手心得，把 AI 變成每天都用得上的即戰力。</span>
    <span class="lc-site"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>林鼎淵 Dean Lin</span>
  </span>
</a>

<p><strong>想將 AI 導入自己的職場與生活嗎？歡迎<a href="https://www.books.com.tw/products/0011004216">購買筆者出版的新書</a></strong>，幫助您<strong>在 AI 的浪潮中站穩腳步，並在未來的職場競爭中佔據優勢！</strong></p>
<figure class="figure"><img src="https://deanlin.net/blog/202303/python-youtube-to-mp3-with-chatgpt/images/python-youtube-to-mp3-with-chatgpt-13.webp" width="1400" height="319" alt="林鼎淵著作《ChatGPT 與 AI 繪圖效率大師（新增 Copilot、Gamma、Runway、Suno）》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.books.com.tw/products/0011004216">https://www.books.com.tw/products/0011004216</a></figcaption>
</figure>

]]></content:encoded>
    </item>
  </channel>
</rss>
