Sorry

This feed does not validate.

In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://blog.serv.idv.tw/feed/

  1. <?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
  2. xmlns:media="http://search.yahoo.com/mrss/"
  3. xmlns:content="http://purl.org/rss/1.0/modules/content/"
  4. xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  5. xmlns:dc="http://purl.org/dc/elements/1.1/"
  6. xmlns:atom="http://www.w3.org/2005/Atom"
  7. xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  8. xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  9. >
  10.  
  11. <channel>
  12. <title>終極邊疆 BLOG</title>
  13. <atom:link href="https://blog.serv.idv.tw/feed/" rel="self" type="application/rss+xml" />
  14. <link>https://blog.serv.idv.tw</link>
  15. <description>在這個時代, blogging 就像是深呼吸一樣。</description>
  16. <lastBuildDate>Thu, 17 Jul 2025 05:43:55 +0000</lastBuildDate>
  17. <language>zh-TW</language>
  18. <sy:updatePeriod>
  19. hourly </sy:updatePeriod>
  20. <sy:updateFrequency>
  21. 1 </sy:updateFrequency>
  22.  
  23. <image>
  24. <url>https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2005/04/cropped-Me-at-Flickr_400.jpg?fit=32%2C32&#038;ssl=1</url>
  25. <title>終極邊疆 BLOG</title>
  26. <link>https://blog.serv.idv.tw</link>
  27. <width>32</width>
  28. <height>32</height>
  29. </image>
  30. <site xmlns="com-wordpress:feed-additions:1">33236058</site> <item>
  31. <title>日本跑步路線 &#8211; 橫濱港未來21</title>
  32. <link>https://blog.serv.idv.tw/2025/07/route-japan-yokohama/</link>
  33. <comments>https://blog.serv.idv.tw/2025/07/route-japan-yokohama/#respond</comments>
  34. <dc:creator><![CDATA[PipperL]]></dc:creator>
  35. <pubDate>Thu, 17 Jul 2025 00:05:00 +0000</pubDate>
  36. <category><![CDATA[運動.初心]]></category>
  37. <category><![CDATA[running]]></category>
  38. <category><![CDATA[日本]]></category>
  39. <category><![CDATA[橫濱]]></category>
  40. <category><![CDATA[跑步]]></category>
  41. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8345</guid>
  42.  
  43. <description><![CDATA[這一篇是2025/7 去日本旅遊時旅跑的路線分享, 這次跑了三條路線: 本篇分享的是在橫濱港 未來21 區域的 ... <a title="日本跑步路線 &#8211; 橫濱港未來21" class="read-more" href="https://blog.serv.idv.tw/2025/07/route-japan-yokohama/" aria-label="Read more about 日本跑步路線 &#8211; 橫濱港未來21">閱讀全文</a>]]></description>
  44. <content:encoded><![CDATA[
  45. <p>這一篇是2025/7 去日本旅遊時旅跑的路線分享,</p>
  46.  
  47.  
  48.  
  49. <p>這次跑了三條路線:</p>
  50.  
  51.  
  52.  
  53. <ol class="wp-block-list">
  54. <li>富士山下 東富士,在靜岡縣的小山町,沿著富士美華resort 附近繞一圈,大概5K 左右。除了我以外,沒有碰到任何其他的人。</li>
  55.  
  56.  
  57.  
  58. <li>橫濱港未來21 (Minatomirai) ,沿著港區繞一圈,距離大概 6K。早上很多跑步的人,但以休閒跑步為主。</li>
  59.  
  60.  
  61.  
  62. <li>千葉港 (Chiba minato) :在千葉港站附近沿著港區跑,距離大約6K。會遇見不少認真的跑者和釣客。</li>
  63. </ol>
  64.  
  65.  
  66.  
  67. <p>本篇分享的是在<strong>橫濱港 未來21 區域</strong>的跑步體驗。</p>
  68.  
  69.  
  70.  
  71. <span id="more-8345"></span>
  72.  
  73.  
  74.  
  75. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  76.  
  77.  
  78.  
  79. <p>我還記得<a href="https://blog.serv.idv.tw/2008/12/%e6%a9%ab%e6%bf%b1%e5%bf%ab%e5%af%ab/">第一次來橫濱</a>的時候,腦子裡還滿滿的是出差、Yokohama show、還有拉麵。當時穿著西裝,混在滿滿一群忙碌的日本上班族中,從一棟樓走到另一棟樓,中午時分,從攤位買個冷掉的日式便當,找張板凳,說聲「不好意思」,然後就著不認識的日本人,各自低頭解決掉便當之後,再分頭繼續各自的行程。</p>
  80.  
  81.  
  82.  
  83. <p>這一次,我穿著短褲,在清晨4點半,跑在沒有太多人的街道,經過遛著狗的日本大叔,在港區和穿著運動服、一樣是享受著日出和港區風光的市民跑者擦身而過。等到櫻木町湧出大量的西裝筆挺上班族時,我已經回到飯店,梳洗完畢,準備今天旅遊的行程了。</p>
  84.  
  85.  
  86.  
  87. <figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
  88. <figure class="wp-block-image size-large"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="768" height="1024" data-id="8350" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8817.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8350" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8817-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8817-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8817-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8817-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8817-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="(max-width: 768px) 100vw, 768px" /></figure>
  89.  
  90.  
  91.  
  92. <figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="1024" height="1024" data-id="8367" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?resize=1024%2C1024&#038;ssl=1" alt="" class="wp-image-8367" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?resize=1024%2C1024&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?resize=400%2C400&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?resize=150%2C150&amp;ssl=1 150w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?resize=1536%2C1536&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?resize=2048%2C2048&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?resize=120%2C120&amp;ssl=1 120w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8941.jpeg?w=2325&amp;ssl=1 2325w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
  93. </figure>
  94.  
  95.  
  96.  
  97. <p>這次住在<a href="https://maps.app.goo.gl/BR2f4sCcZScvyAC5A">橫濱東急REI</a>,是一家現代化的商務型酒店,很適合商務旅客和觀光客,離車站或是主要景點都不遠。</p>
  98.  
  99.  
  100.  
  101. <p>今天規劃要跑路線很簡單,先往北跑到 Tochinoki-dori Ave(栃木通),再往東一直跑到港邊,然後沿著港邊一路往南跑,想跑多遠就跑多遠,最後再往西接到 Nat&#8217;l Rte 133 後,沿著 Nat&#8217;l Rte 133往西北跑回來。</p>
  102.  
  103.  
  104.  
  105. <p>港未來21這一區就像重劃區一樣,路大又直,街道寬敞,兩旁辦公室和飯店高樓林立 (會影響到一些 GPS 收訊),人行道設計完善。也種植了許多樹木,環境整潔,適合清晨慢跑。往東邊一直跑,到了盡頭後,就是臨港公園了。</p>
  106.  
  107.  
  108.  
  109. <figure class="wp-block-image alignwide size-large"><img data-recalc-dims="1" decoding="async" width="1024" height="576" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8829.jpeg?resize=1024%2C576&#038;ssl=1" alt="" class="wp-image-8351" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8829-scaled.jpeg?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8829-scaled.jpeg?resize=400%2C225&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8829-scaled.jpeg?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8829-scaled.jpeg?resize=2048%2C1152&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8829-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
  110.  
  111.  
  112.  
  113. <figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
  114. <figure class="wp-block-image size-large is-style-default"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" data-id="8352" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8836.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8352" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8836-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8836-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8836-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8836-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8836-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  115.  
  116.  
  117.  
  118. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" data-id="8353" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8865.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8353" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8865-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8865-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8865-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8865-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8865-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  119. </figure>
  120.  
  121.  
  122.  
  123. <p></p>
  124.  
  125.  
  126.  
  127. <p>臨港公園是橫濱最大的綠地之一,於1980年代末隨著港未來地區的開發而建成。公園裡有個 <a href="https://maps.app.goo.gl/B3za2FJxBLdvtHbu7">Anchor objet d&#8217;art</a>,回來查了一下,好像資訊並不多。本以為是開港第一艘船的錨…再往前會經過一小座拱橋,小到應該是造景用的。這座拱橋叫 Rinko Park Arch Bridge。</p>
  128.  
  129.  
  130.  
  131. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  132. <p>這座拱橋於2001年作為橫濱三年展(Yokohama Triennale)的一部分正式亮相,由日本雕塑家豐田豊(Yutaka Toyota)設計,象徵日本與巴西之間長達百年的友誼,巴西聖保羅也有一座類似的橋,朝向橫濱的方向,象徵兩地的連結。</p>
  133. </blockquote>
  134.  
  135.  
  136.  
  137. <p>在Rinko Park Arch Bridge 上有個標誌: BAYWALK Yokohama START 0KM (RINKO Park)。<a href="https://www.yokohamaport.org/news/7530/">這一條步道</a>全長大約5K,從臨港公園開始,途經普卡里碼頭、紅磚倉庫、山下公園(Yamashita Park)等地。讓遊客可以沿著橫濱灣的海岸線,探索港未來地區的各大景點。這次時間不夠,下次有機會再全部走一次。</p>
  138.  
  139.  
  140.  
  141. <p>這裡會有一些跑者出沒,有的看起來跟我一樣是觀光客,有的像是固定在這邊運動的。但因為這裡是港灣步道,適合的還是以輕鬆跑為主。跟擦身而過的日本跑者打聲招呼,各自用自己熟悉的步伐前進,</p>
  142.  
  143.  
  144.  
  145. <figure class="wp-block-image alignfull size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8856.jpeg?resize=1024%2C768&#038;ssl=1" alt="" class="wp-image-8349" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8856-scaled.jpeg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8856-scaled.jpeg?resize=400%2C300&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8856-scaled.jpeg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8856-scaled.jpeg?resize=2048%2C1536&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8856-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  146.  
  147.  
  148.  
  149. <p>沿著港邊跑一小段,太陽已經冒出海面,位置正好落在 JERA Yokohama 火力發電廠的兩根煙囪中間。有位大叔架了腳架,用長焦在補捉日出,不過靠過去看太失禮了,只好遠遠地仿照他的角度,猜想可能的取景。</p>
  150.  
  151.  
  152.  
  153. <p>上一次旅跑在水邊看日出…好像是日月潭?兩者都讓人覺得感動。</p>
  154.  
  155.  
  156.  
  157. <figure class="wp-block-image alignwide size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8868.jpeg?resize=1024%2C768&#038;ssl=1" alt="" class="wp-image-8354" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8868.jpeg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8868.jpeg?resize=400%2C300&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8868.jpeg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8868.jpeg?resize=2048%2C1536&amp;ssl=1 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  158.  
  159.  
  160.  
  161. <div class="wp-block-jetpack-tiled-gallery aligncenter is-style-rectangular"><div class=""><div class="tiled-gallery__gallery"><div class="tiled-gallery__row"><div class="tiled-gallery__col" style="flex-basis:50.00000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg?strip=info&#038;w=2000&#038;ssl=1 2000w" alt="" data-height="1920" data-id="8355" data-link="https://blog.serv.idv.tw/?attachment_id=8355#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg" data-width="2560" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8873-1024x768.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 1 張圖片,共 2 張圖片"/></figure></div><div class="tiled-gallery__col" style="flex-basis:50.00000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg?strip=info&#038;w=2000&#038;ssl=1 2000w" alt="" data-height="1920" data-id="8356" data-link="https://blog.serv.idv.tw/?attachment_id=8356#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg" data-width="2560" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8875-1024x768.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 2 張圖片,共 2 張圖片"/></figure></div></div></div></div></div>
  162.  
  163.  
  164.  
  165. <p>再往前,經過 普卡利碼頭(Pukari Sanbashi Pier)後,右手邊看得到地標 Cosmo Clock 21 摩天輪還有雲霄飛車。<br>我喜歡 Pukari Pier 的造型,剛剛升起的日光灑在洋樓和旁邊的觀光船上,真的很美。</p>
  166.  
  167.  
  168.  
  169. <p>再往前,是 新港碼頭客運中心( Shinko Pier Cruise terminal) 。這裡之前是新港碼頭,建設始於1899年,於1917年完工,是橫濱港第一座現代化碼頭,當時用於貨物裝卸,無需依賴駁船。後來在1923年關東大地震中受損,保留了歷史性的紅磚倉庫和鎚頭起重機(Hammerhead Crane)等結構。</p>
  170.  
  171.  
  172.  
  173. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  174. <p>新港碼頭客運中心 (Shinko Pier Cruise terminal) 則是由橫濱市政府與當地企業合作,採取公私合營(PPP)模式,於2018年6月動工,2019年11月完工。碼頭總面積約30,290平方米,延伸至340米長,水深9.5米,可停靠最大11萬噸的郵輪。建築採用現代化設計,結合商業、酒店和海事功能,五層建築包括底層的海關、移民和檢疫(CIQ)設施,以及上層的「InterContinental Yokohama Pier 8」豪華酒店。碼頭周邊還開發了鎚頭公園(Hammerhead Park)和步道,與海濱環境融為一體。也成為日本首個集客運碼頭、酒店和商業設施於一體的綜合設施,標誌著新港地區的現代化轉型。</p>
  175. </blockquote>
  176.  
  177.  
  178.  
  179. <p></p>
  180.  
  181.  
  182.  
  183. <figure class="wp-block-image alignwide size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8898.jpeg?resize=1024%2C768&#038;ssl=1" alt="" class="wp-image-8359" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8898-scaled.jpeg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8898-scaled.jpeg?resize=400%2C300&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8898-scaled.jpeg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8898-scaled.jpeg?resize=2048%2C1536&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8898-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  184.  
  185.  
  186.  
  187. <div class="wp-block-jetpack-tiled-gallery aligncenter is-style-rectangular"><div class=""><div class="tiled-gallery__gallery"><div class="tiled-gallery__row"><div class="tiled-gallery__col" style="flex-basis:50.00000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg?strip=info&#038;w=2000&#038;ssl=1 2000w" alt="" data-height="1920" data-id="8358" data-link="https://blog.serv.idv.tw/?attachment_id=8358#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg" data-width="2560" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8885-1024x768.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 1 張圖片,共 2 張圖片"/></figure></div><div class="tiled-gallery__col" style="flex-basis:50.00000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg?strip=info&#038;w=2000&#038;ssl=1 2000w" alt="" data-height="1920" data-id="8357" data-link="https://blog.serv.idv.tw/?attachment_id=8357#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg" data-width="2560" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8879-1024x768.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 2 張圖片,共 2 張圖片"/></figure></div></div></div></div></div>
  188.  
  189.  
  190.  
  191. <p>再往前,繞過 橫濱海上防災基地(海上保安廳,Yokohama Maritime Disaster Prevention Base),就會看得到著名的觀光客景點 紅磚倉庫了。</p>
  192.  
  193.  
  194.  
  195. <p>紅磚倉庫現在的角色很像高雄的駁二,一開始是作為的保稅倉庫,用於儲存進出口貨物。後來因港口功能轉移而閒置。2002年,倉庫改建成集購物、餐飲和文化活動於一體的綜合設施。就倉庫的數量和空間而言,我覺得駁二更有味道。</p>
  196.  
  197.  
  198.  
  199. <p>跑過紅磚倉庫,左手邊有個小碼頭,名字叫 Pier Aka-Renga,也是坐觀光船的。從航路圖看起來除了A點來回外,好像也有A-B點的選擇。不過就班次表來看,一天開沒有幾班…</p>
  200.  
  201.  
  202.  
  203. <div class="wp-block-jetpack-tiled-gallery aligncenter is-style-rectangular"><div class=""><div class="tiled-gallery__gallery"><div class="tiled-gallery__row"><div class="tiled-gallery__col" style="flex-basis:53.06000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg?strip=info&#038;w=1920&#038;ssl=1 1920w" alt="" data-height="2560" data-id="8362" data-link="https://blog.serv.idv.tw/?attachment_id=8362#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg" data-width="1920" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8916-768x1024.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 1 張圖片,共 3 張圖片"/></figure></div><div class="tiled-gallery__col" style="flex-basis:46.94000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg?strip=info&#038;w=2000&#038;ssl=1 2000w" alt="" data-height="1920" data-id="8361" data-link="https://blog.serv.idv.tw/?attachment_id=8361#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg" data-width="2560" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8910-1024x768.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 2 張圖片,共 3 張圖片"/></figure><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg?strip=info&#038;w=2000&#038;ssl=1 2000w" alt="" data-height="1920" data-id="8360" data-link="https://blog.serv.idv.tw/?attachment_id=8360#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg" data-width="2560" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8907-1024x768.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 3 張圖片,共 3 張圖片"/></figure></div></div></div></div></div>
  204.  
  205.  
  206.  
  207. <p>看了一下地圖,往前跑到象之鼻公園,就要轉彎準備往回程了。象之鼻公園有著很有趣的車擋,名稱來自其獨特的防波堤形狀,彎曲的堤岸從空中俯瞰形似大象的鼻子。這裡有人行空橋可以通往下一區,不過因為我要回程,就要走平面往橫濱稅關的方向前進。</p>
  208.  
  209.  
  210.  
  211. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  212. <p>橫濱稅關(Yokohama Customs House),別稱「女王塔」(Queen’s Tower),建於1917年,是日本明治時代的重要海關建築。(Queen&#8217;s Squere 命名可能跟這也有關係)。橫濱港於1859年開港後,成為日本對外貿易的門戶,稅關負責處理進出口貨物的報關和稅務。現今的建築於1934年重建,經歷了關東大地震的考驗,至今仍是橫濱港的標誌性建築之一。</p>
  213.  
  214.  
  215.  
  216. <p>橫濱稅關由日本建築師大熊喜邦設計,採用鋼筋混凝土結構,外牆以綠色瓷磚裝飾,塔頂的圓形穹頂靈感來自歐洲古典建築,展現明治時代的西式風格。建築內部保留了歷史性的木質地板和裝飾,資料館則以互動展品為主,包括舊報關文件、船模和海關制服。夜間的燈光設計讓女王塔在海濱背景下更顯優雅。</p>
  217. </blockquote>
  218.  
  219.  
  220.  
  221. <p>路上我看到有空橋連結舊和新的大樓建築,上面還掛了布條,提倡太陽能發電,蠻有趣的。</p>
  222.  
  223.  
  224.  
  225. <figure class="wp-block-image alignwide size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8918.jpeg?resize=1024%2C576&#038;ssl=1" alt="" class="wp-image-8364" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8918-scaled.jpeg?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8918-scaled.jpeg?resize=400%2C225&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8918-scaled.jpeg?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8918-scaled.jpeg?resize=2048%2C1152&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8918-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  226.  
  227.  
  228.  
  229. <div class="wp-block-jetpack-tiled-gallery is-style-rectangular"><div class=""><div class="tiled-gallery__gallery"><div class="tiled-gallery__row"><div class="tiled-gallery__col" style="flex-basis:50.00000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg?strip=info&#038;w=1920&#038;ssl=1 1920w" alt="" data-height="2560" data-id="8363" data-link="https://blog.serv.idv.tw/?attachment_id=8363#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg" data-width="1920" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8917-768x1024.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 1 張圖片,共 2 張圖片"/></figure></div><div class="tiled-gallery__col" style="flex-basis:50.00000%"><figure class="tiled-gallery__item"><img decoding="async" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg?strip=info&#038;w=600&#038;ssl=1 600w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg?strip=info&#038;w=900&#038;ssl=1 900w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg?strip=info&#038;w=1200&#038;ssl=1 1200w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg?strip=info&#038;w=1500&#038;ssl=1 1500w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg?strip=info&#038;w=1800&#038;ssl=1 1800w,https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg?strip=info&#038;w=1920&#038;ssl=1 1920w" alt="" data-height="2560" data-id="8366" data-link="https://blog.serv.idv.tw/?attachment_id=8366#main" data-url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg" data-width="1920" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8934-768x1024.jpeg?ssl=1" data-amp-layout="responsive" aria-label="以全螢幕開啟第 2 張圖片,共 2 張圖片"/></figure></div></div></div></div></div>
  230.  
  231.  
  232.  
  233. <p>到 Nat&#8217;l Rte 133 後右轉 沿著 Nat&#8217;l Rte 133 一直跑,快到櫻木町時左手邊還可以看得到<a href="https://blog.serv.idv.tw/2008/12/%e6%a9%ab%e6%bf%b1%e5%bf%ab%e5%af%ab/">當年住宿</a>的櫻木町華盛頓飯店。這麼多年了,飯店外觀保持得還蠻好的,不知道內裝如何? (回來查了資料,飯店在2020年還有翻新過一次)</p>
  234.  
  235.  
  236.  
  237. <p>這條路白天是很熱鬧的,但一大早的時候車流量還很少,經過Landmark tower後,不知不覺就回到起點飯店了。</p>
  238.  
  239.  
  240.  
  241. <p></p>
  242.  
  243.  
  244.  
  245. <p>人生真是有趣,十幾年前來橫濱時,占據心頭的是工作上的衝剌,讓我印象深刻的是夜晚,包括購物、拉麵、打光夜景和城市夜晚的天際線;這一次再訪橫濱,喜歡的卻是燈光退卻後的早晨,朝起的陽光輕撫著這個還沒完全起床的城市,和一些跑者、釣客、鴿子、還有烏鴉,一起感受讓人一直想跑下去的涼風。</p>
  246.  
  247.  
  248.  
  249. <p>夏天這麼做,最舒服了。</p>
  250.  
  251.  
  252.  
  253. <p></p>
  254.  
  255.  
  256.  
  257. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  258.  
  259.  
  260.  
  261. <h2 class="wp-block-heading" id="-8d0f7778-9947-4119-b8ac-60e0d4dcbe62">跑步路線圖:</h2>
  262.  
  263.  
  264.  
  265. <p>當天路線在<a href="https://www.google.com/maps/d/viewer?mid=111DPrw_bXS-f8UEh88LolhKut_LDHHc&amp;hl=zh-TW&amp;usp=sharing" target="_blank" rel="noreferrer noopener">這裡</a>,有需要可以參考:</p>
  266.  
  267.  
  268.  
  269. <iframe loading="lazy" src="https://www.google.com/maps/d/embed?mid=111DPrw_bXS-f8UEh88LolhKut_LDHHc&#038;hl=zh-TW&#038;ehbc=2E312F" width="640" height="480"></iframe>
  270.  
  271.  
  272.  
  273. <p></p>
  274.  
  275.  
  276.  
  277. <p></p>
  278.  
  279.  
  280.  
  281. <h2 class="wp-block-heading" id="-edb28a44-bdf7-4d20-8955-d37b5fc3a530">其他路線變化</h2>
  282.  
  283.  
  284.  
  285. <ul class="wp-block-list">
  286. <li>因為只規劃6K 左右,我是跑到象之鼻公園左右就往西,不然時間夠應該可以再繼續跑,然後往西接到元町 / 中華街,然後往西北跑到伊勢佐木町,再跑到櫻木町…</li>
  287.  
  288.  
  289.  
  290. <li>也可以考慮沿著 baywalk yokohama 走 (全程5K ),再沿著Minatomirai 地鐵路線回來。 baywalk 的路線可以參照如下 (<a href="https://www.yokohamaport.org/wp-content/uploads/BWY_4th.pdf">PDF 下載</a>)</li>
  291. </ul>
  292.  
  293.  
  294. <div class="wp-block-image">
  295. <figure class="aligncenter size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1162.5" height="820" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/Screenshot-2025-07-14-at-11-04-40-BWY_4th.pdf1_.jpeg?resize=1162.5%2C820&#038;ssl=1" alt="" class="wp-image-8346" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/Screenshot-2025-07-14-at-11-04-40-BWY_4th.pdf1_.jpeg?w=2260&amp;ssl=1 2260w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/Screenshot-2025-07-14-at-11-04-40-BWY_4th.pdf1_.jpeg?resize=400%2C282&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/Screenshot-2025-07-14-at-11-04-40-BWY_4th.pdf1_.jpeg?resize=1024%2C723&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/Screenshot-2025-07-14-at-11-04-40-BWY_4th.pdf1_.jpeg?resize=1536%2C1084&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/Screenshot-2025-07-14-at-11-04-40-BWY_4th.pdf1_.jpeg?resize=2048%2C1445&amp;ssl=1 2048w" sizes="auto, (max-width: 1162px) 100vw, 1162px" /></figure></div>
  296.  
  297.  
  298. <h2 class="wp-block-heading" id="one-more-thing-dee63de9-e8fc-4518-b828-8c47a302fd72">One more thing:</h2>
  299.  
  300.  
  301.  
  302. <ul class="wp-block-list">
  303. <li>原來 <a href="https://en.wikipedia.org/wiki/Japan_National_Route_133">Nat’l Rte 133</a> (National Route 133) 是條全長只有 1.4公里的國道。但它不是日本最短的國道。日本最短的國道是國道174號(National Route 174),位於神戶市(Kobe),全長僅0.7公里(0.43英里)。這條國道從神戶港(Kobe Port)到神戶市中央區的一個交匯處,是目前日本國道系統中最短的路線。</li>
  304.  
  305.  
  306.  
  307. <li>而Nat’l Rte 133 也不是排名第二短的國道。日本第二短的國道是國道130號(National Route 130):位於東京,連接東京港與國道15號,全長約0.9公里。<br></li>
  308. </ul>
  309. ]]></content:encoded>
  310. <wfw:commentRss>https://blog.serv.idv.tw/2025/07/route-japan-yokohama/feed/</wfw:commentRss>
  311. <slash:comments>0</slash:comments>
  312. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8929-scaled.jpeg" medium="image"></media:content>
  313.            <post-id xmlns="com-wordpress:feed-additions:1">8345</post-id> </item>
  314. <item>
  315. <title>日本跑步路線 &#8211; 富士山下 東富士</title>
  316. <link>https://blog.serv.idv.tw/2025/07/route-japan-higashi-fuji/</link>
  317. <comments>https://blog.serv.idv.tw/2025/07/route-japan-higashi-fuji/#respond</comments>
  318. <dc:creator><![CDATA[PipperL]]></dc:creator>
  319. <pubDate>Mon, 14 Jul 2025 02:08:47 +0000</pubDate>
  320. <category><![CDATA[運動.初心]]></category>
  321. <category><![CDATA[running]]></category>
  322. <category><![CDATA[富士山]]></category>
  323. <category><![CDATA[日本]]></category>
  324. <category><![CDATA[跑步]]></category>
  325. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8323</guid>
  326.  
  327. <description><![CDATA[趁著去關東地區走走,也抽空用旅跑的方式認識日本。 日本的夏天,天亮的很早,早上4:05左右天邊就魚肚白,4:3 ... <a title="日本跑步路線 &#8211; 富士山下 東富士" class="read-more" href="https://blog.serv.idv.tw/2025/07/route-japan-higashi-fuji/" aria-label="Read more about 日本跑步路線 &#8211; 富士山下 東富士">閱讀全文</a>]]></description>
  328. <content:encoded><![CDATA[
  329. <p>趁著去關東地區走走,也抽空用旅跑的方式認識日本。</p>
  330.  
  331.  
  332.  
  333. <p>日本的夏天,天亮的很早,早上4:05左右天邊就魚肚白,4:35左右天就亮了。要早起跑步的話,晚上得要早點睡、或是犧牲些睡眠時間,然後白天再抓時間補個眠…</p>
  334.  
  335.  
  336.  
  337. <p>今年(2025) 七月份跟台灣一樣炎熱,沒事還是早點在日出左右出門,跑完早早回旅館盥洗、把跑衣洗好、用浴巾壓乾,然後掛起晾乾(或者收進行李等移動到下一間旅館再取出晾乾)。考量到早上6:30之後要配合起床、整理行李、吃早餐等等的行程,跑個5~10K 是沒什麼問題的。</p>
  338.  
  339.  
  340.  
  341. <p></p>
  342.  
  343.  
  344.  
  345. <p>這次跑了三條路線:</p>
  346.  
  347.  
  348.  
  349. <ol class="wp-block-list">
  350. <li>富士山下 東富士 (Higashi-Fuji),在靜岡縣的小山町,沿著富士美華resort 附近繞一圈,大概5K 左右。除了我以外,沒有碰到任何其他的人。</li>
  351.  
  352.  
  353.  
  354. <li>橫濱港未來21 (Minatomirai) ,沿著港區繞一圈,距離大概 6K。早上很多跑步的人,但以休閒跑步為主。</li>
  355.  
  356.  
  357.  
  358. <li>千葉港 (Chiba minato) :在千葉港站附近沿著港區跑,距離大約6K。會遇見不少認真的跑者和釣客。</li>
  359. </ol>
  360.  
  361.  
  362.  
  363. <p>這一篇先寫富士山下的跑步體驗,其他兩篇寫好後會再陸續分享出來。</p>
  364.  
  365.  
  366.  
  367. <span id="more-8323"></span>
  368.  
  369.  
  370.  
  371. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  372.  
  373.  
  374.  
  375. <p>因為住在<a href="https://maps.app.goo.gl/G5WecX8oixPq6F8o8">富士美華 resort </a>,所以出發後也只有兩個選擇:往西或是往東。我選擇往西,因為是朝富士山方向跑過去,希望運氣好能看得到遠方的富士山。</p>
  376.  
  377.  
  378.  
  379. <p>當天能見度並不是特別好,在飯店時是看的到富士山,但不是特別清楚的那一種。跑在Subashiri 路上往西,道路是上坡,但不至於到讓人氣喘噓噓。兩旁的森林跟植被都蠻茂密,林相高且筆直。海拔不到 800 (手表顯示680左右),不是針葉林。跑在樹旁,已經是「身在此山中」,完全看不到遠方的山,更別提一開始想到邊跑邊欣賞富士山的願望了。早上的空氣帶點溼氣,有種像溪頭或是杉林溪那種冷冷溼溼的感覺。沒有車、沒有燈、也沒有人,整條路就只有我一個,映著已經魚肚白的天色好奇地往前跑著。</p>
  380.  
  381.  
  382.  
  383. <figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
  384. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" data-id="8324" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8402.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8324" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8402-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8402-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8402-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8402-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8402-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  385.  
  386.  
  387.  
  388. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" data-id="8325" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8403.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8325" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8403-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8403-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8403-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8403-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8403-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  389.  
  390.  
  391.  
  392. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" data-id="8326" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8406.jpeg?resize=1024%2C768&#038;ssl=1" alt="" class="wp-image-8326" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8406-scaled.jpeg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8406-scaled.jpeg?resize=400%2C300&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8406-scaled.jpeg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8406-scaled.jpeg?resize=2048%2C1536&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8406-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  393. </figure>
  394.  
  395.  
  396.  
  397. <p></p>
  398.  
  399.  
  400.  
  401. <p>Subashiri 道路的盡頭是縣道418,,這裡有一個牌子,寫著東富士 Research Park,還標示了幾間座落在這個研究園區的公司。雖然我不知道為什麼我的飯店會座落在這個「研究園區」,更別提回程路上還會經過高爾夫球場,但還是覺得蠻有趣的。</p>
  402.  
  403.  
  404.  
  405. <p>穿過國道138的高架道路下後左轉,開始往東南跑,這一段路邊有人行道/自行車道(?),不用擔心跑在馬路上的問題。高架道路上偶爾有車經過,聽得到聲音卻看不到,除此之外就是一片寧靜。跑到右方出現一片停車場和一棟建築物 (Fuji Zakura Hotel),有個路口寫 「HOSPITALITY No.1 入口 800m」就可以準備左轉了。</p>
  406.  
  407.  
  408.  
  409. <figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex">
  410. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" data-id="8327" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8418.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8327" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8418-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8418-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8418-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8418-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8418-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  411.  
  412.  
  413.  
  414. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" data-id="8328" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8422.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8328" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8422-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8422-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8422-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8422-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8422-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  415.  
  416.  
  417.  
  418. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" data-id="8329" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8426.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8329" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8426-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8426-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8426-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8426-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8426-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  419. </figure>
  420.  
  421.  
  422.  
  423. <p>轉進 足柄停車場富士公園線 (Shizuoka Prefectural Rte 150) 後,右手邊就是高爾夫球場 富士平原高爾夫俱樂部 ( 富士平原ゴルフクラブ ) ,筆直的道路延伸至遠方,搭配緩緩的下坡,跑起來更是舒服。快到門口和右手邊停車場時,往左後方看,可以有條路和一個「往第3駐車場」的指標。沿著這條路跑回去,可以接回飯店附近的小型居住區域。再繞一下,就可以回到飯店的入口。</p>
  424.  
  425.  
  426.  
  427. <p>也就是在這個時刻,我就著飯店旁的邊坡,終於看到富士山。至少,有完成今天跑步想看到的景。</p>
  428.  
  429.  
  430.  
  431. <figure class="wp-block-image alignwide size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="768" height="1024" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8454.jpeg?resize=768%2C1024&#038;ssl=1" alt="" class="wp-image-8331" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8454-scaled.jpeg?resize=768%2C1024&amp;ssl=1 768w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8454-scaled.jpeg?resize=300%2C400&amp;ssl=1 300w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8454-scaled.jpeg?resize=1152%2C1536&amp;ssl=1 1152w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8454-scaled.jpeg?resize=1536%2C2048&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8454-scaled.jpeg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure>
  432.  
  433.  
  434.  
  435. <p>當然,要看得更清楚點,還是得回到飯店,在樓層較高的地方,會有更好的視野。</p>
  436.  
  437.  
  438.  
  439. <p>回到跑步本身,這裡我覺得是適合跑步的。如果是在這裡渡假,早上可以繞大圈一點,跑個10K 或半馬,享受寧靜和森林,再回飯店沖個澡,到9F 餐廳懶洋洋地吃個早餐,順便享用窗外的富士山景色。</p>
  440.  
  441.  
  442.  
  443. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  444.  
  445.  
  446.  
  447. <h2 class="wp-block-heading">跑步路線圖:</h2>
  448.  
  449.  
  450.  
  451. <p>當天路線在<a href="https://www.google.com/maps/d/viewer?mid=114HymOWsLLz-5xPtM7y4gayRXpr6Z_U&amp;hl=zh-TW&amp;usp=sharing">這裡</a>,有需要可以參考: </p>
  452.  
  453.  
  454.  
  455. <iframe loading="lazy" src="https://www.google.com/maps/d/embed?mid=114HymOWsLLz-5xPtM7y4gayRXpr6Z_U&#038;hl=zh-TW&#038;ehbc=2E312F" width="640" height="480"></iframe>
  456.  
  457.  
  458.  
  459. <p></p>
  460.  
  461.  
  462.  
  463. <p></p>
  464.  
  465.  
  466.  
  467. <h2 class="wp-block-heading">幾個路線的變化:</h2>
  468.  
  469.  
  470.  
  471. <ul class="wp-block-list">
  472. <li>如果不轉進足柄停車場富士公園線,直走的話繼續沿418縣道跑到十字路口,往北走市道7533,再左轉Subashiri,應該也可以。</li>
  473.  
  474.  
  475.  
  476. <li>如果在高爾夫球場繼續直走,一樣會跟市道7533交會,然後往北走,再左轉繞一圈,也是可以。</li>
  477. </ul>
  478.  
  479.  
  480.  
  481. <p></p>
  482.  
  483.  
  484.  
  485. <h2 class="wp-block-heading">One more thing:</h2>
  486.  
  487.  
  488.  
  489. <ul class="wp-block-list">
  490. <li>這裡還有<a href="https://blog.serv.idv.tw/2008/11/%e5%85%a9%e5%80%8b%e8%a7%92%e5%ba%a6%e7%9a%84%e5%af%8c%e5%a3%ab%e5%b1%b1/">另外一個角度的富士山</a>:</li>
  491. </ul>
  492.  
  493.  
  494.  
  495. <figure class="wp-block-image size-large"><img decoding="async" src="https://photo.serv.idv.tw/wp-content/uploads/2008/11/2998801701_e54b99be9d_o.jpg" alt=""/></figure>
  496.  
  497.  
  498.  
  499. <p></p>
  500. ]]></content:encoded>
  501. <wfw:commentRss>https://blog.serv.idv.tw/2025/07/route-japan-higashi-fuji/feed/</wfw:commentRss>
  502. <slash:comments>0</slash:comments>
  503. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/07/IMG_8438-scaled.jpeg" medium="image"></media:content>
  504.            <post-id xmlns="com-wordpress:feed-additions:1">8323</post-id> </item>
  505. <item>
  506. <title>2025Q2 財務盤點</title>
  507. <link>https://blog.serv.idv.tw/2025/07/2025q2-financial-review/</link>
  508. <comments>https://blog.serv.idv.tw/2025/07/2025q2-financial-review/#respond</comments>
  509. <dc:creator><![CDATA[PipperL]]></dc:creator>
  510. <pubDate>Mon, 07 Jul 2025 00:05:00 +0000</pubDate>
  511. <category><![CDATA[FIRE.理財]]></category>
  512. <category><![CDATA[FIRE]]></category>
  513. <category><![CDATA[review]]></category>
  514. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8313</guid>
  515.  
  516. <description><![CDATA[Q2 結束的這個時間點,除了意味著我離職滿一年了,也象徵著「壓力測試期」已經走了一半。 這半年來,試著靠著資產 ... <a title="2025Q2 財務盤點" class="read-more" href="https://blog.serv.idv.tw/2025/07/2025q2-financial-review/" aria-label="Read more about 2025Q2 財務盤點">閱讀全文</a>]]></description>
  517. <content:encoded><![CDATA[
  518. <p>Q2 結束的這個時間點,除了意味著我離職滿一年了,也象徵著「壓力測試期」已經走了一半。</p>
  519.  
  520.  
  521.  
  522. <p>這半年來,試著靠著資產的現金流過活,過程中有焦慮、有意外,也有一些讓人安心的觀察與修正。</p>
  523.  
  524.  
  525.  
  526. <p>這一篇,算是對Q2的生活與財務狀況的回顧。</p>
  527.  
  528.  
  529.  
  530. <p>也是再一次撥開迷霧,更了解自己財務狀態的嘗試。</p>
  531.  
  532.  
  533.  
  534. <p></p>
  535.  
  536.  
  537.  
  538. <span id="more-8313"></span>
  539.  
  540.  
  541.  
  542. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  543.  
  544.  
  545.  
  546. <p></p>
  547.  
  548.  
  549.  
  550. <h2 class="wp-block-heading">支出檢視與檢討</h2>
  551.  
  552.  
  553.  
  554. <p>這季總支出花掉了預算的78.67%。表面看來還在可接受範圍內,也沒有明顯超支。但實際拆開來看,幾個月份的波動很有感,尤其五月的支出高峰,接近單月預算的 125%。主因是孩子學費與稅保支出大幅集中。這幾筆「集中型支出」讓我在想,前幾個月用「每月支出」來追蹤年度花費中每個月的變化,其實是相對粗糙的。像保費、稅金、教育支出、家電更新這幾個項目,都是一次性出現、但金額動輒數萬。如果出現在某幾個月,就會導致該月的支出上升,但這不代表多吃了什麼,或是亂花錢…</p>
  555.  
  556.  
  557.  
  558. <p></p>
  559.  
  560.  
  561.  
  562. <p>以 2024 年為例,全年稅金支出占總支出的 25.8%,保險則為 9.1%。出現的月份集中在固定幾個月。孩子的學費也是,2~3個月一期,如果加疊,可能當月這類的支出就占了超過50%。這些比例遠高於我原本預期,也是變動性高且難以預估的項目。如果用原來每個月的支出來看,這是難以預期/估計的 (當然,固定年繳的保險是可以追蹤的)。但如果拉長到每季或是每年的累計支出,這類的支出相對就比較穩定了。</p>
  563.  
  564.  
  565.  
  566. <p></p>
  567.  
  568.  
  569.  
  570. <p>除了觀察,我也自己加了一些些<strong>實驗</strong>進去:</p>
  571.  
  572.  
  573.  
  574. <p>飲食方面,這季我試著在上館子與自煮之間找出新的平衡。六月份在刻意為之之下,外食比例明顯拉高,飲食支出每月比平常多花三至五千元。這樣的支出換來的是大量節省備料與下廚的時間。</p>
  575.  
  576.  
  577.  
  578. <p>自煮的優勢在於能精確控制食材成本和營養攝取,尤其對於追求健康飲食的人來說,是個經濟又實用的選擇。然而,它的缺點也顯而易見:備餐和烹飪需要花費不少時間,而且菜色容易陷入單調。(好啦,是我的手藝問題)</p>
  579.  
  580.  
  581.  
  582. <p>至於成本,自煮雖然在每餐成本上比外食便宜 20~50%,但如果加上準備時間,效應其實就沒那麼明顯。小家庭煮飯比較難做出「經濟規模」,常常還會剩一堆食材要處理。有時寧願外食——省時、省事、有選擇,只是貴一點而已,時間與腦袋都省下來了。</p>
  583.  
  584.  
  585.  
  586. <p>哪一種值得呢?我沒有標準答案。但經過一季的實驗之後,至少知道上下限大概在哪裡。現在我可以根據心情和時間安排,在自煮與外食間找到更好的平衡 (或任性)。</p>
  587.  
  588.  
  589.  
  590. <p></p>
  591.  
  592.  
  593.  
  594. <p>上次提到四月份川普「對等關稅」可能的衝擊。的確,從心態上來說,四月那波股災確實影響了我對開銷的感受。即使總資產尚未真正「短缺」,但看到資產縮水,還是會冒出「會不會不夠用」的焦慮。那陣子我不自覺地更頻繁打開記帳 app,想看看錢到底花到哪裡去了,離職加上經濟下行,正常人應該都會有這種焦慮。</p>
  595.  
  596.  
  597.  
  598. <p>怎麼克服?我沒有標準答案。目前就是側觀/記錄自己的心態,就跟量子力學一樣,觀察本身,就會對被觀察者造成影響…</p>
  599.  
  600.  
  601.  
  602. <p></p>
  603.  
  604.  
  605.  
  606. <p></p>
  607.  
  608.  
  609.  
  610. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  611.  
  612.  
  613.  
  614. <p></p>
  615.  
  616.  
  617.  
  618. <h2 class="wp-block-heading">收入與資產檢視</h2>
  619.  
  620.  
  621.  
  622. <p>跟<a href="https://blog.serv.idv.tw/2025/04/nomad-51-2025q1-financial-review/">季度期初(Q1 結束)</a>相比,期末 (Q2結束) 時資產減損約 -6.74%。若扣除提領後,實際資產報酬率為 -5.87%。</p>
  623.  
  624.  
  625.  
  626. <p>主因之一是四月初的股災。當時川普再次宣布施行「對等關稅」政策,針對數十個國家啟動高額懲罰性關稅,包括中國、德國、日本與台灣,部分商品稅率甚至高達 50%。消息一出,美股三大指數在三天內暴跌 9~11%,科技股重挫最多超過 15%。雖然五月中後市場因談判與關稅暫緩而回穩,但我的投資組合仍難以完全避免衝擊。</p>
  627.  
  628.  
  629.  
  630. <p>第二個影響因素是台幣強勢升值。五月底到六月間,台幣對美元從 33.07 一路升值到 29.56 (六月底,七月初又升值到28.x),升幅達 10.7%。這造成我帳上的美元資產即便以美元計價是成長的(+3.5%) ,但折合新台幣後卻又變成虧損 (-7.49%)。這讓我一度再想需不需要做台外幣的再平衡,但我真的很不想這麼麻煩…</p>
  631.  
  632.  
  633.  
  634. <p>回顧四月初的心情,「什麼也不做」應該是相對正確的選擇。雖然乍看之下好像「錯過」了逢底搶進的那一波,不過我不是那一派的,什麼都不做看起來依舊是最適合我,也是從事後來看最合理的作法。</p>
  635.  
  636.  
  637.  
  638. <p></p>
  639.  
  640.  
  641.  
  642. <p>資產配置方面,目前現金與定存佔 5.89%,國內股票 34.98%,國外股票 39.45%,債券 13.91%,以及收益護盾(如 YMAG 等)5.79%。本季股債比約為 84.25 : 15.75,略低於上一季的債券比例。後續預計會再增加一點點債的部位。</p>
  643.  
  644.  
  645.  
  646. <p>另外因為最近手上有一些台幣,我把部分台幣資產換成美元,再透過複委託投入 BOXX 當作定存使用。但也因此承受了台幣繼續升值的風險。</p>
  647.  
  648.  
  649.  
  650. <p></p>
  651.  
  652.  
  653.  
  654. <p>主動的部份最值得檢討: YMAG,這個我實驗性納入的期權 ETF,以「高配息、低波動」為賣點 (實際上表現…不一定如此)。從這季數據來看,帳面淨值下跌 16.6%,即使加上已領配息,整體報酬率也只有 -3.28%。雖然我拿來作為收益護盾使用,實際上在這幾個月的觀察發現,它的「現金流」其實是在「淨值/本金減損」下產生的。這類商品表面上提供了高額/高比例的配息,但淨值減損的程度遠超過想像。即使含息報酬為正的部份商品,跟他追蹤的原型股比起來,其實是「少賺」的。也就是說,如果去投資原型股的話,其實資本成長還更多。</p>
  655.  
  656.  
  657.  
  658. <p>市場穩定的時候,這類ETF 可以提供穩定的配息 (搭配淨值減損);<br>當波動性激增時,期權策略容易失靈,導致淨值快速蒸發。尤其是在股災時,這類期權ETF在劇烈波動下,會同時出現淨值與配息雙雙下滑的慘狀。(aka 「淨值跌、配息減」的死亡螺旋)<br>如果當市場穩定緩步成長時,除了提供穩定的配息之外,還有機會賺到淨值 (但其實羊毛出在羊身上… 原型股成長更多)</p>
  659.  
  660.  
  661.  
  662. <p>雖然這些配息可以提供一定的情緒價值,讓自己在股災的時候看到戶頭有錢進來。但如果想像那是從淨值賣掉扣30%後再配給你的,就沒那麼好心情了。</p>
  663.  
  664.  
  665.  
  666. <p>這樣的表現算是「收益護盾」嗎?我覺得不是。但的確可以提供現金流,避免長期投資部份的賣出和減損。也就是說,護盾是護盾沒錯,但比較像是心理價值的護盾,比較像是避免賣出長期資產的護盾。而包括淨值減損的含配息價值減損,就當作是高額的手續費吧…</p>
  667.  
  668.  
  669.  
  670. <p></p>
  671.  
  672.  
  673.  
  674. <p>目前,我決定手上的 YMAG 繼續持有,因為我想知道後續到底會怎麼樣。未來我需要再另外重新設計收益護盾,尋找更穩健的現金流方案。</p>
  675.  
  676.  
  677.  
  678. <p></p>
  679.  
  680.  
  681.  
  682. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  683.  
  684.  
  685.  
  686. <p></p>
  687.  
  688.  
  689.  
  690. <h2 class="wp-block-heading">總結</h2>
  691.  
  692.  
  693.  
  694. <p>走完第二季,壓力測試期已經過了一半。很慶幸四月的股災和五月的匯率帶來考驗,雖然沒有觀察到熊市的來臨,但還是對得起壓力測試的本意。這幾個月,我更清楚看到支出結構中的重點項目,例如稅金、保險和教育費用,也愈來愈能面對自己的心態變化。資產部分雖然經歷了政策與匯率的雙重震盪,但整體配置並未出現明顯失衡,繼續呈現一定的韌性,讓我對FIRE生活的可持續性更有信心。但收益護盾的不足也提醒我,如何設計穩定現金流,需要更進一步的重新規劃。天下真的沒有白吃的午餐。</p>
  695.  
  696.  
  697.  
  698. <p>一如我在Q1 寫的:</p>
  699.  
  700.  
  701.  
  702. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  703. <p>目前我是打算把手綁起來,等一個月後再進去收拾戰場。這種局有人拚翻身,但我不需要翻身,所以走的是損失趨避,等大盤指數回來。</p>
  704. </blockquote>
  705.  
  706.  
  707.  
  708. <p>一季過去,還真的回來了…</p>
  709.  
  710.  
  711.  
  712. <p>接下來Q3 會面臨大額支出的挑戰 (所得稅 + 出國旅遊旅費),又是觀察自己面對另一種支出型態的心態和心境。壓力測試本來就不是為了證明一切完美無缺,而是讓自己提早看到問題,做出調整。繼續「練心」 —— 練習面對外界的變化,以及內觀自己的心態。 —— 是我今年的目標之一。 </p>
  713.  
  714.  
  715.  
  716. <p>當我越來越不被帳面數字牽著走,就愈能好好過生活,好好把我的注意力,用在珍貴的生活裡。</p>
  717.  
  718.  
  719.  
  720. <p>這條路還長,但我看看腳下踩的腳印,已經愈來愈清楚。</p>
  721.  
  722.  
  723.  
  724. <p></p>
  725. ]]></content:encoded>
  726. <wfw:commentRss>https://blog.serv.idv.tw/2025/07/2025q2-financial-review/feed/</wfw:commentRss>
  727. <slash:comments>0</slash:comments>
  728. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2024/08/DALL·E-2024-08-24-19.50.32-An-image-depicting-a-reflective-and-organized-workspace-where-someone-is-reviewing-their-financial-situation.-The-desk-has-a-laptop-displaying-charts--e1724500422551.webp" medium="image"></media:content>
  729.            <post-id xmlns="com-wordpress:feed-additions:1">8313</post-id> </item>
  730. <item>
  731. <title>六月做什麼</title>
  732. <link>https://blog.serv.idv.tw/2025/06/june-playing-with-kids/</link>
  733. <comments>https://blog.serv.idv.tw/2025/06/june-playing-with-kids/#respond</comments>
  734. <dc:creator><![CDATA[PipperL]]></dc:creator>
  735. <pubDate>Mon, 30 Jun 2025 00:05:00 +0000</pubDate>
  736. <category><![CDATA[GTD]]></category>
  737. <category><![CDATA[小平安計畫]]></category>
  738. <category><![CDATA[小幸福計畫]]></category>
  739. <category><![CDATA[小平安]]></category>
  740. <category><![CDATA[小幸福]]></category>
  741. <category><![CDATA[會考]]></category>
  742. <category><![CDATA[注意力]]></category>
  743. <category><![CDATA[社群媒體]]></category>
  744. <category><![CDATA[遊戲]]></category>
  745. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8300</guid>
  746.  
  747. <description><![CDATA[六月快結束了,接下來是暑假。今天在想,六月發生什麼值得記錄的事呢? 除了從Pocket 跳船到 Keep,學了 ... <a title="六月做什麼" class="read-more" href="https://blog.serv.idv.tw/2025/06/june-playing-with-kids/" aria-label="Read more about 六月做什麼">閱讀全文</a>]]></description>
  748. <content:encoded><![CDATA[
  749. <p>六月快結束了,接下來是暑假。<br>今天在想,六月發生什麼值得記錄的事呢?</p>
  750.  
  751.  
  752.  
  753. <p>除了<a href="https://blog.serv.idv.tw/2025/06/from-pocket-to-karakeep/">從Pocket 跳船到 Keep</a>,<a href="https://blog.serv.idv.tw/2025/06/n8n-workflow-karakeep/">學了 n8n</a> ,<a href="https://blog.serv.idv.tw/2025/06/colab-whisperx-transcript-revised-50619/">重改了 Colab+ WhisperX 腳本</a>之外,生活裡,印象較深的就是跟兩個孩子一起玩遊戲和課業吧。</p>
  754.  
  755.  
  756.  
  757. <p>又要玩又要顧課業,還真的是 study hard, play hard.</p>
  758.  
  759.  
  760.  
  761. <span id="more-8300"></span>
  762.  
  763.  
  764.  
  765. <p></p>
  766.  
  767.  
  768.  
  769. <p></p>
  770.  
  771.  
  772.  
  773. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  774.  
  775.  
  776.  
  777. <p></p>
  778.  
  779.  
  780.  
  781. <h2 class="wp-block-heading">與小平安的遊戲時光</h2>
  782.  
  783.  
  784.  
  785. <p>過去兩年來,我一直有在「陪」兩個孩子玩手機遊戲: <a href="https://www.pokemonunite.jp/tc/">Pokemon Unite</a>。我也已經忘記動機是什麼了,一開始是創了一個角色,陪小幸福玩,她玩遠攻輸出,我就玩坦。當時小平安還不到10歲,不能玩,只能在一旁看。然後當小平安10歲之後,很快他創了角色,走近戰風,我們三個就常在週末假日約時間一起玩。</p>
  786.  
  787.  
  788.  
  789. <p>他們兩位在電玩上比我有天份多了,不管是走位,操作,技能和道具配置,或是戰術策略,面對不同敵人的處理方式,都比我純熟多了。很快地,我就從坦,變成被他們carry 的角色。等級或排位,這兩位也是遠遠地超越我。我不意外,畢竟我一開始只是「陪玩」的心態, 但這樣的陪伴,卻帶給我無價的親子時光和滿滿的歡笑… 好啦,還是有衝突的時候,尤其是當我們這隊輸的時候,大家心情不好,開始檢討隊友的時候。此時我最常「被檢討」…畢竟我是三人裡最弱的角色。</p>
  790.  
  791.  
  792.  
  793. <p>六月,我手上有一個遊戲想玩很久了,所以邀請小平安一起玩《<a href="https://zh.wikipedia.org/zh-tw/%E5%8F%8C%E4%BA%BA%E6%88%90%E8%A1%8C">雙人成行</a>》(It Takes Two)。這款遊戲是一款合作冒險遊戲,於2021年由霧影工作室開發,二代雙影奇境最近才上市。玩家需要兩人協作完成各種解謎和動作挑戰。我看小平安平常蠻喜歡玩跑酷類的遊戲,之前我玩「A Story about My Uncle」時他也常湊過來看,甚至在一些關卡接手破關。我相信他對這方面的遊戲是有興趣的,雖然問他時,他總是會說「啊…我可能會3D 暈」,但是把控制器交到他手上後,身體卻又很誠實地玩了起來。</p>
  794.  
  795.  
  796. <div class="wp-block-image">
  797. <figure class="aligncenter size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/it-takes-two-%E9%9B%99%E4%BA%BA%E6%88%90%E8%A1%8C-%E9%81%8A%E6%88%B2.jpg?resize=1024%2C576&#038;ssl=1" alt="" class="wp-image-8302" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/it-takes-two-%E9%9B%99%E4%BA%BA%E6%88%90%E8%A1%8C-%E9%81%8A%E6%88%B2.jpg?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/it-takes-two-%E9%9B%99%E4%BA%BA%E6%88%90%E8%A1%8C-%E9%81%8A%E6%88%B2.jpg?resize=400%2C225&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/it-takes-two-%E9%9B%99%E4%BA%BA%E6%88%90%E8%A1%8C-%E9%81%8A%E6%88%B2.jpg?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/it-takes-two-%E9%9B%99%E4%BA%BA%E6%88%90%E8%A1%8C-%E9%81%8A%E6%88%B2.jpg?w=2000&amp;ssl=1 2000w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>
  798.  
  799.  
  800. <p>雙人成行的劇情圍繞一對面臨婚姻危機的夫妻被魔法變成玩偶後的冒險故事。開始玩之後,小平安看起來對主創劇情的推進和夫妻逐一面對婚姻的課題並沒有興趣,但對於各個關卡對人物的不同玩法操作他卻深深著迷。他最喜歡在城堡地牢化身魔法師的那段,看起來是以後可以揪去玩 Diablo 的玩伴。裡頭有許多場景讓他跑酷,我還在探索主線要如何推進時,他已經四處遊山玩水,把遊戲裡的空氣牆和死角都探了個遍。我在玩遊戲時注重情節的走向,想知道主線的下一段會怎麼走,該如何觸發;他則是不厭煩地玩著目前這個場景可以爬、可以跳、可以互動的所有設置 &#8212; 包括哪裡/怎樣才會死,死了會在哪裡重生…</p>
  801.  
  802.  
  803.  
  804. <p>跟他一起玩,真的讓我體驗到遊戲心態的不同。</p>
  805.  
  806.  
  807.  
  808. <p>而不只是我學到東西,他也是。因為遊戲對於死亡是沒有什麼penalty 的 (會不斷重生),再加上之前玩 minecraft 的習慣。我發現他走路不好好的走,總是跳跳跳,我走到懸崖邊會停下來看看路,想一想接下來怎麼一路跳/盪過去;他則是用瞬間的判斷力和走位先飛出去,然後在空中接續下一步。好處是行雲流水但常常捏一把冷汗,缺點就是常常跳空、煞不住、重生後沒想清楚就衝出去…然後又掛了。</p>
  809.  
  810.  
  811.  
  812. <p>幾次之後,就換我碎碎念要他先停下來冷靜一下… 這種場景在拿到他考卷,問他這題為什麼錯的時候,好像也會發生。有時是題目看太快,看前幾個字就寫答案了;有時是檢查的時候跳過這一題… 他在遊戲中即時判斷的能力,有助於在考試中快速答榮,但也可能導致缺乏耐心檢查答案。這部份我就只在遊戲中提醒他,希望他有機會可以自己思考。</p>
  813.  
  814.  
  815.  
  816. <p></p>
  817.  
  818.  
  819.  
  820. <p>但在某些點上,他卻也有他的執著和堅持。</p>
  821.  
  822.  
  823.  
  824. <p>玩遊戲跟考試,應該也是有些相似的地方…</p>
  825.  
  826.  
  827.  
  828. <p>總之,六月份的雙人成行,我跟小平安都玩的很開心。全破之後,現在開始解成就跟解鎖全部的小遊戲,順便回去複習喜愛的關卡。照這個態勢,應該有機會推坑他一起玩雙影奇境。</p>
  829.  
  830.  
  831.  
  832. <p>至於小幸福…已經喊+1 想要玩了。但…她真的有時間嗎?</p>
  833.  
  834.  
  835.  
  836. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  837.  
  838.  
  839.  
  840. <p></p>
  841.  
  842.  
  843.  
  844. <h2 class="wp-block-heading">小幸福開始面對一年後的會考</h2>
  845.  
  846.  
  847.  
  848. <p>小幸福已經要升國三了。六月份老師開始安排學長姐回校講座,傳授國三會考的準備方式以及高中以後的生涯規劃。再加上國三學長姐會考的成績陸續出爐,家長們開始討論、比較。我自己體感「會考」這個跟過去聯考很像的大考,壓力慢慢罩在小幸福的頭上。</p>
  849.  
  850.  
  851.  
  852. <p>不過就我的觀察,壓力在罩在孩子的頭上之前,是先罩在家長們的頭上的。身邊家長們的焦慮情緒逐漸升溫,但孩子還不一定有。言談中她心思還是在玩手遊、玩社群,讀書的部份就交給學校和補習班。</p>
  853.  
  854.  
  855.  
  856. <p>這當然跟「家長的期待」有一段…<strong>很&#8230;大…的gap</strong>。</p>
  857.  
  858.  
  859.  
  860. <p>家長對會考的期待往往帶有強烈的目標導向。希望孩子能考進理想的高中,為未來的競爭鋪路。這種期待不僅來自對孩子未來的關心,也受到社會氛圍的影響。六月,當學長姐的講座和會考成績的公布接踵而來,身邊的家長們開始頻繁交流,討論孩子的進度、總複習補習班,以及模擬考的日期和考試範圍。這種氛圍讓我感到壓力,進而將期望轉嫁到孩子身上。導致我自己在這個月,時常思考如何讓小幸福認真面對一年後的會考,同時確保她不會因為壓力過大而失去學習的動力。</p>
  861.  
  862.  
  863.  
  864. <p>好啦,跟其他家長比起來,我可能還算是後知後覺的…</p>
  865.  
  866.  
  867.  
  868. <p></p>
  869.  
  870.  
  871.  
  872. <p>小幸福的反應,與我的期待形成鮮明對比。對她來說,會考的壓力還很遙遠,手遊和社群媒體才是當下更吸引她的焦點。對她而言,讀書就是去學校和補習班時會發生的事。回家把學校的功課寫完後,就想放鬆一下。這種「唸好眼前的進度,然後玩樂休息」的抗拒心態,與家長「規劃好,必須全力以赴」的期待產生衝突。這種衝突並不罕見,許多國中學生在這個階段都面臨類似的拉鋸戰。對孩子而言,會考的意義可能不如即時的娛樂來得具體,而家長的焦慮則來自對未來的長期規劃,兩者的時間視野和優先順序截然不同。</p>
  873.  
  874.  
  875.  
  876. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  877. <p>AI 告訴我:這種期待與抗拒的衝突,其實反映了親子間的溝通挑戰。家長往往希望孩子能理解會考的重要性,但忽略了孩子可能還在探索自我,尚未完全準備好承擔這樣的壓力。對小幸福來說,手遊和社群媒體不僅是娛樂,也是她與同學互動、建立認同感的方式。完全禁止這些活動可能適得其反,讓她感到被剝奪自由,甚至對學習產生更大的抗拒。</p>
  878. </blockquote>
  879.  
  880.  
  881.  
  882. <p></p>
  883.  
  884.  
  885.  
  886. <p>再加上身處青春期,即使之前在情感銀行裡存了不少存款,要提領出來還是得要小心翼翼。</p>
  887.  
  888.  
  889.  
  890. <p></p>
  891.  
  892.  
  893.  
  894. <p>我認為化解這種衝突的關鍵,在於理解與對話,以及「慢一點」(都焦慮了還要慢一點?)。我開始與小幸福分享我年輕時學習的經驗,以及我認為現在這個時代,學習的方式和工具已經跟過去(我那個年代)不同。我並沒有「現代學習工具」的標準解答,但我試著跟他分享我現在看到的,「供她參考」。</p>
  895.  
  896.  
  897.  
  898. <p></p>
  899.  
  900.  
  901.  
  902. <p>是的,<strong>「供參考」這幾個字很重要</strong>。</p>
  903.  
  904.  
  905.  
  906. <p></p>
  907.  
  908.  
  909.  
  910. <p>就像刷題型一樣,我提供我面對這種題型,以一個四十多歲的大叔…和家長的觀點。但如果她想要用其他的方法解一題,只要解得出來,我還是樂觀其成,頂多再給點意見。</p>
  911.  
  912.  
  913.  
  914. <p>不過就我這一個月來的觀察,與其說是不知道,不如說是「不焦慮」和「不想做」。</p>
  915.  
  916.  
  917.  
  918. <p></p>
  919.  
  920.  
  921.  
  922. <p><strong>不焦慮是相對的,相對於我而言。</strong></p>
  923.  
  924.  
  925.  
  926. <p><strong>不想做這件事,只能靠她自己。</strong></p>
  927.  
  928.  
  929.  
  930. <p></p>
  931.  
  932.  
  933.  
  934. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  935. <p>在處於自我認同與獨立性探索的階段,這個年紀的青少年更關注與同儕的社交關係和自我興趣。小幸福對手遊和社群媒體的投入,是她試圖透過這些管道,建立同儕認同和自我價值感。相比之下,會考的壓力對她來說是抽象且遙遠的,這解釋了她為何缺乏我感受到的焦慮。從研究上來看,青少年對即時滿足(instant gratification)的追求往往高於對未來目標的關注,這與大腦前額葉皮質(負責長期規劃和自我控制)的發育尚未成熟有關。(雖然說,成人在現在數位時代的獎勵陷阱中,表現也沒有好到哪兒去)</p>
  936.  
  937.  
  938.  
  939. <p>而,「不想做」,很顯然跟內在動機不足有關。根據自我決定論(Self-Determination Theory, SDT),人類行為的動機來自三種基本心理需求:自主性(autonomy)、勝任/能力感(competence)和歸屬/關係(relatedness)。當孩子感到學習是被迫的,或缺乏自主選擇的空間時,他們的內在動機會下降。</p>
  940. </blockquote>
  941.  
  942.  
  943.  
  944. <p>當家長、學校和補習班幫忙把學習網都架好,良善的動機和想像通常是:「我幫你把工具資源都架好,那麼你學習就輕鬆了。」但學生會這樣想嗎?還是反而會因為這是外部所加,而減緩她內心自我驅動的部份?如果當青少年在學習中缺乏成就感或控制感時,他們會不會更傾向於能快速提供滿足感的活動,如遊戲或社群媒體?</p>
  945.  
  946.  
  947.  
  948. <p>另外,社會比較(social comparison)也可能間接影響小幸福的態度。家長間的討論和對成績的比較,雖然對家長來說是尋求資訊和支持的方式,但可能無意中加劇了孩子的壓力或抗拒。當感受到與他人的比較壓力時,我們可能選擇逃避或轉向其他領域來維護自我價值。所以也有可能,小幸福因為察覺到家長的期待與自身能力之間的差距,而選擇專注於她擅長且能獲得即時回饋的領域,例如遊戲。 (正好也是我相對不擅長的)</p>
  949.  
  950.  
  951.  
  952. <p>最後,數位時代的環境也是一個重要因素。社群媒體和手遊的設計利用了多巴胺驅動的反饋機制(dopamine-driven feedback loops),讓青少年難以抗拒這些即時刺激。大腦對這些高刺激活動的偏好,在注意力有限的情況之下,她就選擇了手機,而不是需要長期投入的學業。</p>
  953.  
  954.  
  955.  
  956. <p></p>
  957.  
  958.  
  959.  
  960. <p>那我該怎麼辦呢?</p>
  961.  
  962.  
  963.  
  964. <p></p>
  965.  
  966.  
  967.  
  968. <h2 class="wp-block-heading">以身作責,最佳化我的注意力</h2>
  969.  
  970.  
  971.  
  972. <p>我是相信身教的。</p>
  973.  
  974.  
  975.  
  976. <p>現在社會中,在餐廳裡,有時看到一家四口坐在一桌,然後各自滑著手機,吃著面前的餐點。這是我儘可能避免的。</p>
  977.  
  978.  
  979.  
  980. <p>為了向小幸福示範注意力和面對長期目標的作法,我開始重新審視資訊接收的習慣。</p>
  981.  
  982.  
  983.  
  984. <p>首先,我開始減少瀏覽社群媒體的時間,尤其是「海巡」式的登入各大社群服務去看今日的熱門話題,以及打開 App 後的無意識滑動。我將主要的資訊來源設定為 RSS 訂閱和電子報,這些管道能提供更精準、結構化的內容,而且來自於我事先選好的範疇。對於 Twitter 和臉書,我刻意保留App 上的廣告。這種使用上的不便和反感,可以降低自己頻繁查看的動力。上週,我還<a href="https://blog.serv.idv.tw/2025/06/techjobntalk-line-comminuty/">退出了幾個 LINE 大群</a>。</p>
  985.  
  986.  
  987.  
  988. <p></p>
  989.  
  990.  
  991.  
  992. <p>再來,我利用自動化工具來簡化例行工作。藉著學習n8n的機會,我打造了一套給我自己用的自動化流程,包括之前提到的 <a href="https://blog.serv.idv.tw/2025/06/n8n-workflow-karakeep/">karakeep 打星分享</a>,以及一些服務的運作狀態通知。理想上,只有在系統出問題時我才會收到通知,其他時候這些檢查都在背景默默運行。這樣的設定讓我能將注意力集中在更有創造性、更重要的任務上。減少定期檢查服務狀態的心思。</p>
  993.  
  994.  
  995.  
  996. <p>製作這些工具的目的,都是要釋放我自己的注意力,專注於重要的事情。</p>
  997.  
  998.  
  999.  
  1000. <p></p>
  1001.  
  1002.  
  1003.  
  1004. <h2 class="wp-block-heading">以身作責,作長期目標的示範</h2>
  1005.  
  1006.  
  1007.  
  1008. <p>這一塊目前我想要用 GTD 和專案管理 的方式來做。之前有稍微跟小幸福聊過 GTD 的方式。對我而言,將這些方法應用於長期目標的管理,我自己已經很純熟,也在職場中跟同事們分享。但如何帶一個青少年實作,而且是在自我內在動機不夠強烈的情況下,我是蠻傷腦筋的。但我還是想要以自己在家裡的作法,讓她看到這種結構化方法的價值。</p>
  1009.  
  1010.  
  1011.  
  1012. <p>如果可以,我當然很樂意用這一套方式,為小幸福規劃準備會考的處理方式,例如:</p>
  1013.  
  1014.  
  1015.  
  1016. <ul class="wp-block-list">
  1017. <li><strong>收集 (Capture)</strong>:讓小幸福把所有要寫的題目、要複習的範圍、要學習的新進度等想法,用筆記本或App記錄下來。</li>
  1018.  
  1019.  
  1020.  
  1021. <li><strong>整理 (Clarify)</strong>:將這些想法分類,判斷哪些是立即可做的,哪些需要長期規劃。</li>
  1022.  
  1023.  
  1024.  
  1025. <li><strong>組織 (Organize)</strong>:把任務分配到每日或每週計畫中,例如每天花一小時複習數學,每週做一次模擬考。</li>
  1026.  
  1027.  
  1028.  
  1029. <li><strong>檢視 (Review)</strong>:每週與她一起回顧進度,看看哪些任務完成了,哪些需要調整。</li>
  1030.  
  1031.  
  1032.  
  1033. <li><strong>執行(Do)</strong>:鼓勵她在指定時間 (目前是用番茄鐘方式) 專注完成單一任務,避免分心。</li>
  1034. </ul>
  1035.  
  1036.  
  1037.  
  1038. <p>但現在這麼做,反而會落入前面提到的陷阱,減損她的自我驅動動機。</p>
  1039.  
  1040.  
  1041.  
  1042. <p></p>
  1043.  
  1044.  
  1045.  
  1046. <p>所以我目前只有跟他分享 GTD 的架構,與我手上的事情如何用這套方式拆解成 下一步動作 (Next Action, NA),然後實作。我會與她分享我之前如何用 GTD 管理自己的工作,如何分解一個專案並按時完成。我也會和她分享我工作時的筆記和相關工具。主要還是做在我自己身上,示範給她看。</p>
  1047.  
  1048.  
  1049.  
  1050. <p>目前我的觀察,GTD 的部份她自己有開始使用小本子作 to list,至少有初步的 Capture 跟 Clarify。但目前還是有點三天打漁兩天曬網。所以… 我只能繼續等待。</p>
  1051.  
  1052.  
  1053.  
  1054. <p>而專案管理,那就離他更遠了。</p>
  1055.  
  1056.  
  1057.  
  1058. <p>往好處想,即將到來的暑假,延續去年的「<a href="https://blog.serv.idv.tw/2024/07/nomad-wk-11/">貓咪暑假計畫</a>」,今年他們兩位在準備上已經熟門熟路。希望在一起整理下週的任務的同時,可以看得到她的成長。</p>
  1059.  
  1060.  
  1061.  
  1062. <p>總之,這一 part 我也是邊做邊看,自己也沒有什麼把握。自己會跟教到別人會,尤其是自己孩子,真是一件不容易的事。</p>
  1063.  
  1064.  
  1065.  
  1066. <p></p>
  1067.  
  1068.  
  1069.  
  1070. <p></p>
  1071. ]]></content:encoded>
  1072. <wfw:commentRss>https://blog.serv.idv.tw/2025/06/june-playing-with-kids/feed/</wfw:commentRss>
  1073. <slash:comments>0</slash:comments>
  1074. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/06/880152706046542437.jpeg" medium="image"></media:content>
  1075.            <post-id xmlns="com-wordpress:feed-additions:1">8300</post-id> </item>
  1076. <item>
  1077. <title>對科技工作講LINE社群的觀察</title>
  1078. <link>https://blog.serv.idv.tw/2025/06/techjobntalk-line-comminuty/</link>
  1079. <comments>https://blog.serv.idv.tw/2025/06/techjobntalk-line-comminuty/#respond</comments>
  1080. <dc:creator><![CDATA[PipperL]]></dc:creator>
  1081. <pubDate>Mon, 23 Jun 2025 09:05:00 +0000</pubDate>
  1082. <category><![CDATA[社群]]></category>
  1083. <category><![CDATA[社會觀察]]></category>
  1084. <category><![CDATA[科技工作講]]></category>
  1085. <category><![CDATA[管理]]></category>
  1086. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8279</guid>
  1087.  
  1088. <description><![CDATA[我應該是在 clubhouse 時期開始收聽科技工作講的,後來隨著這個科技從業者社群的成長和演化,也開始固定聽 ... <a title="對科技工作講LINE社群的觀察" class="read-more" href="https://blog.serv.idv.tw/2025/06/techjobntalk-line-comminuty/" aria-label="Read more about 對科技工作講LINE社群的觀察">閱讀全文</a>]]></description>
  1089. <content:encoded><![CDATA[
  1090. <p>我應該是在 <a href="https://www.clubhouse.com/">clubhouse</a> 時期開始收聽科技工作講的,後來隨著這個科技從業者社群的成長和演化,<a href="https://linktr.ee/Techjobntalk">也開始固定聽podcast</a>、偶爾聽每週的youtube 直播 (如果題目有興趣,想現場討論的話)。我也追蹤了臉書粉絲頁,閱讀主理人抹布的觀點和言論、加入了LINE 社群、甚至連 telegram 群組都加入過。</p>
  1091.  
  1092.  
  1093.  
  1094. <p>這篇文章是針對 科技工作講 LINE 社群的一些觀察和個人觀點。不一定100% 客觀和全面。</p>
  1095.  
  1096.  
  1097.  
  1098. <p></p>
  1099.  
  1100.  
  1101.  
  1102. <p>簡單說,我要退群了。</p>
  1103.  
  1104.  
  1105.  
  1106. <span id="more-8279"></span>
  1107.  
  1108.  
  1109.  
  1110. <p></p>
  1111.  
  1112.  
  1113.  
  1114. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  1115.  
  1116.  
  1117.  
  1118. <p></p>
  1119.  
  1120.  
  1121.  
  1122. <p>我個人當初 加入科技工作講 LINE 社群是期待一個專業建議、每週節目內容討論、以及相互取暖的園地。雖然科技業範圍很大,從半導體設計、製造、到機械、到軟體都有,而角色從RD、PM (這個大宗)、行銷、Q、SCM 都有。真的要找到跟自己100% 背景符合的,要看運氣。但如果放開到「可以互相對話,聽得懂行話」,那還是可以湊齊一隻手 (雖然前前後後,人們來來去去)。</p>
  1123.  
  1124.  
  1125.  
  1126. <p>總之,那是一個在工作環境圈子之外,可以分享和傾聽科技業從業生活、科技圈事件和話題、從業者心情分享和抉擇的園地。</p>
  1127.  
  1128.  
  1129.  
  1130. <p>至少一開始是如此的。</p>
  1131.  
  1132.  
  1133.  
  1134. <p>隨著加入的人數愈來愈多,開始出現小群/專業群,細分成更專業或是特定族群:專業的部份 IC、PM、DA、QA、SWE、AI… 等職業分群出現了;族群部份休閒群、理財群、親子群…也出現了;這還不包括地區性的社群 (如新竹小群) 以及個人私建的群組。這些小群雖然掛著科技工作講的名號,其實是相對獨立的。各個群由熱心的群友創群作為管理者,科技工作講的主理人抹布 moboo 本身不直接管理這些社群,只是在大群裡有記事本和 bot 把有興趣的人導流至這些較小的社群,同時讓這些社群掛上科技工作講的名號。</p>
  1135.  
  1136.  
  1137.  
  1138. <p>原始大群在全盛時期接近五千人,因為社群人數的上限還開了二群。現在人數維持四千多人,管理者有5 位,但實際的管板者只有1~2位。科技工作講主理人抹布雖然掛在管理者的名單上,但其實「管板」這件事,主要還是交給熱心的群友。至於抹布參與討論的頻率,就我個人的體感,早期比較多一點,現在已經很少。如果要看抹布說了什麼,或是要和他互動,到科技工作講的粉專還比較有效。其他的管理者有在處理事情的,大概只剩1~2人。4000人的社群,要靠1個管理者管板,就我的觀點和經驗,其實是非常不足的。這個情況下,社群的發展就很吃運氣跟管理者的專業。</p>
  1139.  
  1140.  
  1141.  
  1142. <p></p>
  1143.  
  1144.  
  1145.  
  1146. <h2 class="wp-block-heading">我觀察到的社群經營問題</h2>
  1147.  
  1148.  
  1149.  
  1150. <p>說運氣,是因為有的社群很幸運,會有一些不是管理者的資深群友,主動自發地經營著這個社群的討論和風氣。如果沒那麼幸運的,就反過來變成亂板。亂板的時候,第二道防線就很重要了:管理者的專業。</p>
  1151.  
  1152.  
  1153.  
  1154. <p></p>
  1155.  
  1156.  
  1157.  
  1158. <h3 class="wp-block-heading">可能的成因之一:不專業的管理者</h3>
  1159.  
  1160.  
  1161.  
  1162. <p>說專業,指的不是科技工作專業,而是管理者的公正性和議題經營的方式。4000人的大群,往往會不定期的有爭議性的言論出現。詐騙廣告這種人人喊砍的,不會有什麼問題;但如果是群友的討論,立場不同的時候,管理者往往會劃下一道紅線,讓言論的討論不至於升高到破壞社群風氣的程度。但紅線怎麼劃,管理者如何執行,以及最重要的,管理者如何給人公正客觀,這是管板的專業。</p>
  1163.  
  1164.  
  1165.  
  1166. <p>很可惜的,就我的觀察,現在的管理員並沒有做的很好。</p>
  1167.  
  1168.  
  1169.  
  1170. <p>舉個群裡最常出現爭議的例子:政治。</p>
  1171.  
  1172.  
  1173.  
  1174. <p>在去年年中以後,為了不要讓政治類的話題在大群裡爭吵,設下了一條規定 「政治議題請到政治子群」。</p>
  1175.  
  1176.  
  1177.  
  1178. <p>那什麼是「政治議題」呢? 當然是以管理員 Ian 認定。<br>一定開始有人試著踩線,踩邊線,測試那條線的位置。但因為管理者個人的政治觀點和立場,我自己的觀察,這條線是會漂移,會隨著發言的人跟發言的立場而改變的。久而久之,雙方立場的人都觀察到了這個現象,跟管理員同政治立場的人,就快樂地踩一下,踩一下,等到管理員出聲了,再收回,但…不會真的到政治子群去討論。</p>
  1179.  
  1180.  
  1181.  
  1182. <p>而對立立場的人,發現檢舉對方談政治議題無效,而自己同樣踩一下踩一下的行為反而為被管理員更嚴格的認定,於是開始主張管理員雙標或是立場不公正。然後…就跟管理員結下樑子了。</p>
  1183.  
  1184.  
  1185.  
  1186. <p>至於管理員,當然自己認為自己沒有雙標,自己是中立且客觀,對雙方都一樣的。只是就我的觀察,在爭議性的話題或是政治議題的言論出現後,他有時會先發言講一下觀點、看法、或評論,然後緊接一句:這是政治議題,後續請到政治子群討論。</p>
  1187.  
  1188.  
  1189.  
  1190. <p>那這個議題會到政治子群被討論嗎?並沒有。</p>
  1191.  
  1192.  
  1193.  
  1194. <p>對立場對立的發言者而言,這個議題在管理者(親某方立場)的發言之後,被沒收(不能再繼續討論)了。</p>
  1195.  
  1196.  
  1197.  
  1198. <p></p>
  1199.  
  1200.  
  1201.  
  1202. <p>更糟的是,有時(接近政治議題)的討論裡,管理員的發言會讓人分不清楚,他是以管理員的角色在執法/判斷,還是以對立立場在酸/針對/參與。這就像是在路上被警察攔下來,但開口討論的是昨晚你們爭論不休的議題。</p>
  1203.  
  1204.  
  1205.  
  1206. <p>你以為他是以個人立場在討論,講著講著他又會以管理者的權限要求討論要平和、有意義、或是不牽涉政治。</p>
  1207.  
  1208.  
  1209.  
  1210. <p>你以為他是要出來執法,但他的發言卻又針對某人和過去的恩怨作個人觀點/評判/質疑。</p>
  1211.  
  1212.  
  1213.  
  1214. <p></p>
  1215.  
  1216.  
  1217. <div class="wp-block-image">
  1218. <figure class="aligncenter size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1162.5" height="655" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/%E6%B2%92%E6%94%B6%E5%8A%9F%E5%B0%B1%E7%BD%B5%E9%AB%92%E8%A9%B1_L.jpg?resize=1162.5%2C655&#038;ssl=1" alt="" class="wp-image-8284" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/%E6%B2%92%E6%94%B6%E5%8A%9F%E5%B0%B1%E7%BD%B5%E9%AB%92%E8%A9%B1_L.jpg?w=2400&amp;ssl=1 2400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/%E6%B2%92%E6%94%B6%E5%8A%9F%E5%B0%B1%E7%BD%B5%E9%AB%92%E8%A9%B1_L.jpg?resize=400%2C225&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/%E6%B2%92%E6%94%B6%E5%8A%9F%E5%B0%B1%E7%BD%B5%E9%AB%92%E8%A9%B1_L.jpg?resize=1024%2C577&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/%E6%B2%92%E6%94%B6%E5%8A%9F%E5%B0%B1%E7%BD%B5%E9%AB%92%E8%A9%B1_L.jpg?resize=1536%2C865&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/%E6%B2%92%E6%94%B6%E5%8A%9F%E5%B0%B1%E7%BD%B5%E9%AB%92%E8%A9%B1_L.jpg?resize=2048%2C1154&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/%E6%B2%92%E6%94%B6%E5%8A%9F%E5%B0%B1%E7%BD%B5%E9%AB%92%E8%A9%B1_L.jpg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1162px) 100vw, 1162px" /></figure></div>
  1219.  
  1220.  
  1221. <p>這些其實一直都是社群/管板者要面對的問題。也因為如此,早期 (從 BBS 年代) 針對這種角色上可能的混淆,就已經有一些應對的措施和規範。包括獨立的管理者帳號,或是將執法和個人的發言作清楚的區分等等。</p>
  1222.  
  1223.  
  1224.  
  1225. <p>在職場上來說也是,為什麼你的好同事升官換了個位子,就不跟你一起在座位嘲笑公司政策和那些過去你們一起看不慣的同事了? </p>
  1226.  
  1227.  
  1228.  
  1229. <p>「換個位子,換個腦袋」沒錯。但這句話,除了字面上的貶意之外,還有更深的用意在裡頭。</p>
  1230.  
  1231.  
  1232.  
  1233. <p></p>
  1234.  
  1235.  
  1236.  
  1237. <p>簡單來說,當你擁有權力的同時,也要特別小心維持管理者/執法者的公正性,以及公私的分明。</p>
  1238.  
  1239.  
  1240.  
  1241. <p>瓜田李下,古早的成語就是人性的寫照。</p>
  1242.  
  1243.  
  1244.  
  1245. <p>在現實生活中,警察的制服、公家機關謝絕選舉造熱或政治活動,都是同樣的出發點。</p>
  1246.  
  1247.  
  1248.  
  1249. <p></p>
  1250.  
  1251.  
  1252.  
  1253. <p>以我的觀點而言,現在管板者的個人好惡、立場、以及一些發言,已經影響到這個社群的討論健康和多元。</p>
  1254.  
  1255.  
  1256.  
  1257. <p>我觀察到一些具有貢獻的群友離開,不是因為對「科技工作講」這個主題不感興趣,而是因為跟其他群友的衝突 &#8212; 包括管板的 Ian。</p>
  1258.  
  1259.  
  1260.  
  1261. <p>這是一個有趣的現象:好的社群管理者應該保障討論的多元和有機,而不是「順耳」的言論。</p>
  1262.  
  1263.  
  1264.  
  1265. <p>當我看到管理者在和志同道合者嘻嘻哈哈的同時,一邊批評著對立觀點的人,他頭像旁的那顆閃亮小皇冠 (具有管理者權力的標示) 真的讓我搖頭。</p>
  1266.  
  1267.  
  1268.  
  1269. <p></p>
  1270.  
  1271.  
  1272.  
  1273. <p>接下來被影響到的,就是風氣經營了。</p>
  1274.  
  1275.  
  1276.  
  1277. <p></p>
  1278.  
  1279.  
  1280.  
  1281. <h3 class="wp-block-heading">可能的成因之二:科技工作講主理人的態度</h3>
  1282.  
  1283.  
  1284.  
  1285. <p>4000人的 LINE 社群,遇到爭議時,沒有一個相對公正的管理;而創群/科技工作講的主理人,抹布,他對於這個社群的想法又是如何呢?</p>
  1286.  
  1287.  
  1288.  
  1289. <p>這個社群雖然掛上科技工作講的名號,但在 2024年5月的深夜,主理人抹布有說過因為當時太忙,他其實是放掉這個社群的。</p>
  1290.  
  1291.  
  1292.  
  1293. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="766" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/IMG_8033.jpg?resize=1024%2C766&#038;ssl=1" alt="去年 moboo 的發言" class="wp-image-8281" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/IMG_8033.jpg?resize=1024%2C766&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/IMG_8033.jpg?resize=400%2C299&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/IMG_8033.jpg?w=1179&amp;ssl=1 1179w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  1294.  
  1295.  
  1296.  
  1297. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  1298. <p>對,因為沒有時間經營<br>去年接主管之後晚上還要跟美國溝通,所以改成開社團讓大家留言,去年時間還比較多,<br>今年因為合併的新的團隊,現在我還要跟軟體溝通,必須要放掉這邊</p>
  1299. </blockquote>
  1300.  
  1301.  
  1302.  
  1303. <p></p>
  1304.  
  1305.  
  1306.  
  1307. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  1308. <p>我感謝你提出想法,其實你知道我是看很長線的人,這某種程度是我選擇先不處理Line群的原因,因為他處理不完。我應該專心在把粉絲團弄大,把Podcast維持下去,就可以弄到更多資源,像是很多科技公司一直想贊助我們下半年活動。我目標是看長看遠</p>
  1309.  
  1310.  
  1311.  
  1312. <p>我理解到大家對於一些人發言感到很不滿,我也跟蘇桑當面說過請他克制一點。之間也跟幾個管理員討論過。其實他們都有在管理。目前是沒有比較強硬把一些人踢出去。這個尺度很難拿捏</p>
  1313.  
  1314.  
  1315.  
  1316. <p>我目前是沒有要求要怎麼做<br>是最近tag我的人變多,我才來,但是前幾天讀這群都當<img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f602.png" alt="😂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
  1317. </blockquote>
  1318.  
  1319.  
  1320.  
  1321. <p>而一年過去了,抹布依舊在臉書粉絲團活躍著,每天都會看到他的文章或發言;但在LINE 社群裡的參與討論或回應,已經是快兩個月前的事情了。因此「放掉LINE 社群」這件事,應該還是跟去年年中時的想法/作法一致。</p>
  1322.  
  1323.  
  1324.  
  1325. <p>也因為這樣,雖然是「科技工作講」 LINE 社群,但跟抹布並沒有太大的關係。過去在直播的同時,LINE 這邊還會有同步的討論,但已經很久沒看到了。這裡的風氣經營、議題設定和發展,已經偏離當初一開始我加入的狀態了。</p>
  1326.  
  1327.  
  1328.  
  1329. <p></p>
  1330.  
  1331.  
  1332.  
  1333. <h2 class="wp-block-heading">那現在討論的風氣如何?</h2>
  1334.  
  1335.  
  1336.  
  1337. <p>就我的體感,現在大群變成另一種…轉貼然後進行時事和國際情勢評論的地方,而且聊著聊著就會往政治那條線靠近,然後管理員再出來沒收討論…  XD</p>
  1338.  
  1339.  
  1340.  
  1341. <p></p>
  1342.  
  1343.  
  1344.  
  1345. <p>為了確認我的體感是否正確,請 ChatGPT 統計了過去14天的話題中,前幾大分類:</p>
  1346.  
  1347.  
  1348.  
  1349. <ul class="wp-block-list">
  1350. <li>職涯發展與工作選擇:這是開群以來的熱門話題,約占兩成。</li>
  1351.  
  1352.  
  1353.  
  1354. <li>社會現象和政治/政策評論:也占兩成左右</li>
  1355.  
  1356.  
  1357.  
  1358. <li>產業與經濟現象:這不限於科技業,話題約 15%</li>
  1359.  
  1360.  
  1361.  
  1362. <li>AI 和科技話題:大概 7%</li>
  1363. </ul>
  1364.  
  1365.  
  1366.  
  1367. <p></p>
  1368.  
  1369.  
  1370.  
  1371. <p>若以發言者的次數來看,其中 80% 的發言集中在5個人身上。以一個4200人的社群而言… 有點怪異。</p>
  1372.  
  1373.  
  1374.  
  1375. <p>如果要細緻或深入一些的討論,還是可以往小群跑。但這很吃小群管理者的風格。而且發言集中在少數幾個人的狀況,在小群其實更加嚴重。每個小群的素質也有顯著的差異。有的已經變成幾個老群友的聊天群了。</p>
  1376.  
  1377.  
  1378.  
  1379. <p></p>
  1380.  
  1381.  
  1382.  
  1383. <p></p>
  1384.  
  1385.  
  1386.  
  1387. <h2 class="wp-block-heading">那未來呢</h2>
  1388.  
  1389.  
  1390.  
  1391. <p>因為這個社群已經4000人,以目前科技業的熱門程度而言,這個群短時間並不會消滅。</p>
  1392.  
  1393.  
  1394.  
  1395. <p>一個社群即使已經可以自己維持生命,要保持健康,我的想法是要討論內容要有機(organic)和保持多樣性(diversity)。</p>
  1396.  
  1397.  
  1398.  
  1399. <p></p>
  1400.  
  1401.  
  1402.  
  1403. <p>以我目前觀察到的「活躍用戶」占的比例,以社群現任管理者面對爭議處理的方式,以抹布對這個LINE社群的態度 (放掉對這個社群的認真經營),不要說是人數不會成長,這個群的「健康」已經下降 (腐敗) 到我也變成吃瓜壁上觀的一員了。</p>
  1404.  
  1405.  
  1406.  
  1407. <p></p>
  1408.  
  1409.  
  1410.  
  1411. <p>即使我跟其他4000人一樣,多數時間只是潛水的大眾;即使這個群偶爾會有具意義和價值的討論,讓我願意貢獻我的兩分錢;即使我使用這個社群的方式是看一下最近討論的話題,並沒有爬過每一則討論;寫文現況的我,仍然覺得這樣子做,浪費了我稀缺的注意力。</p>
  1412.  
  1413.  
  1414.  
  1415. <p></p>
  1416.  
  1417.  
  1418.  
  1419. <p>因此,我覺得跟這個群分手的時間到了。</p>
  1420.  
  1421.  
  1422.  
  1423. <p>podcast 我還是會繼續聽,抹布在粉專的話題也會常常被臉書推到我面前 (但點不點進去,取決於我),部份小群還是會待著,留意一下對科技話題的看法。</p>
  1424.  
  1425.  
  1426.  
  1427. <p>至於已經變質的大群或是太水的小群…就先道再見了。</p>
  1428.  
  1429.  
  1430.  
  1431. <p></p>
  1432.  
  1433.  
  1434.  
  1435. <p></p>
  1436. ]]></content:encoded>
  1437. <wfw:commentRss>https://blog.serv.idv.tw/2025/06/techjobntalk-line-comminuty/feed/</wfw:commentRss>
  1438. <slash:comments>0</slash:comments>
  1439. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/06/banner-社群經營.jpeg" medium="image"></media:content>
  1440.            <post-id xmlns="com-wordpress:feed-additions:1">8279</post-id> </item>
  1441. <item>
  1442. <title>Colab + WhisperX 將音檔轉成逐字稿 (20250619版)</title>
  1443. <link>https://blog.serv.idv.tw/2025/06/colab-whisperx-transcript-revised-50619/</link>
  1444. <comments>https://blog.serv.idv.tw/2025/06/colab-whisperx-transcript-revised-50619/#comments</comments>
  1445. <dc:creator><![CDATA[PipperL]]></dc:creator>
  1446. <pubDate>Thu, 19 Jun 2025 03:01:26 +0000</pubDate>
  1447. <category><![CDATA[電腦.網路]]></category>
  1448. <category><![CDATA[AI]]></category>
  1449. <category><![CDATA[podcast]]></category>
  1450. <category><![CDATA[Python]]></category>
  1451. <category><![CDATA[vibe coding]]></category>
  1452. <category><![CDATA[逐字稿]]></category>
  1453. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8274</guid>
  1454.  
  1455. <description><![CDATA[這兩天有需求,再上 colab 用 WhisperX 把音檔轉成逐字稿。發現之前寫好的code 又跑出錯誤訊息 ... <a title="Colab + WhisperX 將音檔轉成逐字稿 (20250619版)" class="read-more" href="https://blog.serv.idv.tw/2025/06/colab-whisperx-transcript-revised-50619/" aria-label="Read more about Colab + WhisperX 將音檔轉成逐字稿 (20250619版)">閱讀全文</a>]]></description>
  1456. <content:encoded><![CDATA[
  1457. <p>這兩天有需求,再上 colab 用 WhisperX 把音檔轉成逐字稿。發現之前<a href="https://blog.serv.idv.tw/2025/04/colab-whisperx-transcript/">寫好的code </a>又跑出錯誤訊息了。</p>
  1458.  
  1459.  
  1460.  
  1461. <p>解決問題的路上,發現新版已經跑得起來,不用像之前還要移除 Pytorch、安裝特定相容的版本。但版本依賴的狀況還是蠻混亂的。</p>
  1462.  
  1463.  
  1464.  
  1465. <p>新的版本還是帶來新的問題:</p>
  1466.  
  1467.  
  1468.  
  1469. <ul class="wp-block-list">
  1470. <li>whisperx.DiarizationPipeline 指令改成 whisperx.diarize.DiarizationPipeline</li>
  1471.  
  1472.  
  1473.  
  1474. <li>alignment.py 裡有個Index Error,<a href="https://github.com/m-bain/whisperX/issues/1048">Issue 裡也有人回報</a>,但還在等修復,目前需要自己進去改code。</li>
  1475. </ul>
  1476.  
  1477.  
  1478.  
  1479. <p>我整理了一下,再把新的code 放上來,但使用上要小心。再幾個版本後可能又不能用了。</p>
  1480.  
  1481.  
  1482.  
  1483. <p></p>
  1484.  
  1485.  
  1486.  
  1487. <p>目前日期 (2025/6/19)所安裝的版本為:</p>
  1488.  
  1489.  
  1490.  
  1491. <pre class="wp-block-preformatted">whisperx 3.3.4<br>ctranslate2 4.4.0<br>pyannote-audio 3.3.2<br>torch 2.6.0+cu124<br>torchaudio 2.6.0+cu124<br>libcudnn8 8.9.7.29-1+cuda12.2<br>libcudnn8-dev 8.9.7.29-1+cuda12.2</pre>
  1492.  
  1493.  
  1494.  
  1495. <p></p>
  1496.  
  1497.  
  1498.  
  1499. <p>以下是目前的code 跟修改的地方。如果要知道更多 code 的作用,可以回去參考<a href="https://blog.serv.idv.tw/2025/04/colab-whisperx-transcript/">一開始發佈的版本</a>,裡頭有說明。</p>
  1500.  
  1501.  
  1502.  
  1503. <span id="more-8274"></span>
  1504.  
  1505.  
  1506.  
  1507. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  1508.  
  1509.  
  1510.  
  1511. <h2 class="wp-block-heading">Part 1. 掛載 Google Drive</h2>
  1512.  
  1513.  
  1514.  
  1515. <p>這部份沒有什麼改變。</p>
  1516.  
  1517.  
  1518.  
  1519. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>from google.colab import drive
  1520. drive.mount(&#8216;/content/drive&#8217;)</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> google</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">colab </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> drive</span></span>
  1521. <span class="line"><span style="color: #D8DEE9FF">drive</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">mount</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">/content/drive</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span></span></code></pre></div>
  1522.  
  1523.  
  1524.  
  1525. <p></p>
  1526.  
  1527.  
  1528.  
  1529. <p></p>
  1530.  
  1531.  
  1532.  
  1533. <h2 class="wp-block-heading">Part 2. 安裝與環境配置</h2>
  1534.  
  1535.  
  1536.  
  1537. <p>新版變得簡潔許多了。只要記得安裝 libduenn8、whisperx、跟pyannote.audio. </p>
  1538.  
  1539.  
  1540.  
  1541. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>!apt-get update
  1542. !apt install libcudnn8 libcudnn8-dev -y
  1543. !pip install whisperx
  1544. !pip install pyannote.audio
  1545.  
  1546.  
  1547. !python -c &#8220;import torch; torch.backends.cuda.matmul.allow_tf32 = True; torch.backends.cudnn.allow_tf32 = True&#8221;</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">apt</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">get update</span></span>
  1548. <span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">apt install libcudnn8 libcudnn8</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">dev </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">y</span></span>
  1549. <span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">pip install whisperx</span></span>
  1550. <span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">pip install pyannote</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">audio</span></span>
  1551. <span class="line"></span>
  1552. <span class="line"></span>
  1553. <span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">python </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">c </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">import torch; torch.backends.cuda.matmul.allow_tf32 = True; torch.backends.cudnn.allow_tf32 = True</span><span style="color: #ECEFF4">&quot;</span></span></code></pre></div>
  1554.  
  1555.  
  1556.  
  1557. <p></p>
  1558.  
  1559.  
  1560.  
  1561. <h2 class="wp-block-heading">Part 3. 修改alignment.py 原始碼</h2>
  1562.  
  1563.  
  1564.  
  1565. <p>這裡因為要修改 alignment.py 裡的一行原始碼,解決出現 <code>IndexError: tensors used as indices must be long, int, byte or bool tensors </code>的問題,所以需要寫個腳本處理。如果未來 whisperx 新版解決掉這個bug,這一段可能就不需要了。</p>
  1566.  
  1567.  
  1568.  
  1569. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly># 重置環境(可選)
  1570. #%reset -f
  1571.  
  1572. # 安裝或更新 whisperx(如果需要)
  1573. #!pip install &#8211;upgrade whisperx
  1574.  
  1575. # 複製 whisperx 到 /content
  1576. !cp -r /usr/local/lib/python3.11/dist-packages/whisperx /content/whisperx
  1577.  
  1578. # 修改 alignment.py
  1579. import os
  1580. file_path = &#8216;/content/whisperx/alignment.py&#8217;
  1581. with open(file_path, &#8216;r&#8217;) as file:
  1582.    lines = file.readlines()
  1583. target_line = &#8216;regular_scores = frame_emission[tokens.clamp(min=0)]&#8217;
  1584. new_line = &#8216;regular_scores = frame_emission[tokens.clamp(min=0).long()]  # 轉換為 torch.long\n&#8217;
  1585. for i, line in enumerate(lines):
  1586.    if target_line in line:
  1587.        lines[i] = new_line
  1588.        break
  1589. with open(file_path, &#8216;w&#8217;) as file:
  1590.    file.writelines(lines)
  1591. print(&#8220;已修改 alignment.py&#8221;)
  1592.  
  1593. # 驗證修改
  1594. !grep &#8220;regular_scores = frame_emission&#8221; /content/whisperx/alignment.py
  1595.  
  1596. # 清除模組快取
  1597. import sys
  1598. for module in list(sys.modules.keys()):
  1599.    if module.startswith(&#8216;whisperx&#8217;):
  1600.        del sys.modules[module]
  1601. print(&#8220;已清除 whisperx 相關模組&#8221;)
  1602.  
  1603. # 設置 sys.path
  1604. sys.path.insert(0, &#8216;/content&#8217;)
  1605. print(&#8220;sys.path:&#8221;, sys.path)
  1606.  
  1607. # 載入並驗證 whisperx
  1608. import whisperx
  1609. print(&#8220;whisperx 路徑:&#8221;, whisperx.__file__)  # 應為 /content/whisperx/__init__.py
  1610.  
  1611. import os
  1612.  
  1613. file_path = &#8216;/content/whisperx/alignment.py&#8217;
  1614. with open(file_path, &#8216;r&#8217;) as file:
  1615.    lines = file.readlines()
  1616.  
  1617. # 修復 regular_scores 的縮進
  1618. for i, line in enumerate(lines):
  1619.    if &#8216;regular_scores = frame_emission[tokens.clamp(min=0).long()]&#8217; in line:
  1620.        lines[i] = &#8216;    &#8216; + line.lstrip()  # 設置為 4 個空格
  1621.        break
  1622.  
  1623. # 寫回文件
  1624. with open(file_path, &#8216;w&#8217;) as file:
  1625.    file.writelines(lines)
  1626. print(&#8220;已修復 regular_scores 的縮進&#8221;)
  1627.  
  1628. # 驗證修改
  1629. !sed -n &#8216;420,435p&#8217; /content/whisperx/alignment.py
  1630.  
  1631. </textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># 重置環境(可選)</span></span>
  1632. <span class="line"><span style="color: #616E88">#%reset -f</span></span>
  1633. <span class="line"></span>
  1634. <span class="line"><span style="color: #616E88"># 安裝或更新 whisperx(如果需要)</span></span>
  1635. <span class="line"><span style="color: #616E88">#!pip install --upgrade whisperx</span></span>
  1636. <span class="line"></span>
  1637. <span class="line"><span style="color: #616E88"># 複製 whisperx 到 /content</span></span>
  1638. <span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">cp </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">r </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">usr</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">local</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">lib</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">python3</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">11</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">dist</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">packages</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">whisperx </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">content</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">whisperx</span></span>
  1639. <span class="line"></span>
  1640. <span class="line"><span style="color: #616E88"># 修改 alignment.py</span></span>
  1641. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> os</span></span>
  1642. <span class="line"><span style="color: #D8DEE9FF">file_path </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">/content/whisperx/alignment.py</span><span style="color: #ECEFF4">&#39;</span></span>
  1643. <span class="line"><span style="color: #81A1C1">with</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">open</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">file_path</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">r</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> file</span><span style="color: #ECEFF4">:</span></span>
  1644. <span class="line"><span style="color: #D8DEE9FF">    lines </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> file</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">readlines</span><span style="color: #ECEFF4">()</span></span>
  1645. <span class="line"><span style="color: #D8DEE9FF">target_line </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">regular_scores = frame_emission[tokens.clamp(min=0)]</span><span style="color: #ECEFF4">&#39;</span></span>
  1646. <span class="line"><span style="color: #D8DEE9FF">new_line </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">regular_scores = frame_emission[tokens.clamp(min=0).long()]  # 轉換為 torch.long</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&#39;</span></span>
  1647. <span class="line"><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> i</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> line </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">enumerate</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">lines</span><span style="color: #ECEFF4">):</span></span>
  1648. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> target_line </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> line</span><span style="color: #ECEFF4">:</span></span>
  1649. <span class="line"><span style="color: #D8DEE9FF">        lines</span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> new_line</span></span>
  1650. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">break</span></span>
  1651. <span class="line"><span style="color: #81A1C1">with</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">open</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">file_path</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">w</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> file</span><span style="color: #ECEFF4">:</span></span>
  1652. <span class="line"><span style="color: #D8DEE9FF">    file</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">writelines</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">lines</span><span style="color: #ECEFF4">)</span></span>
  1653. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">已修改 alignment.py</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1654. <span class="line"></span>
  1655. <span class="line"><span style="color: #616E88"># 驗證修改</span></span>
  1656. <span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">grep </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">regular_scores = frame_emission</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">content</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">whisperx</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">alignment</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">py</span></span>
  1657. <span class="line"></span>
  1658. <span class="line"><span style="color: #616E88"># 清除模組快取</span></span>
  1659. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> sys</span></span>
  1660. <span class="line"><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> module </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">list</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">sys</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">modules</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">keys</span><span style="color: #ECEFF4">()):</span></span>
  1661. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> module</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">startswith</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">whisperx</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">):</span></span>
  1662. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">del</span><span style="color: #D8DEE9FF"> sys</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">modules</span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9FF">module</span><span style="color: #ECEFF4">]</span></span>
  1663. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">已清除 whisperx 相關模組</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1664. <span class="line"></span>
  1665. <span class="line"><span style="color: #616E88"># 設置 sys.path</span></span>
  1666. <span class="line"><span style="color: #D8DEE9FF">sys</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">path</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">insert</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">/content</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span></span>
  1667. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">sys.path:</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> sys</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">path</span><span style="color: #ECEFF4">)</span></span>
  1668. <span class="line"></span>
  1669. <span class="line"><span style="color: #616E88"># 載入並驗證 whisperx</span></span>
  1670. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> whisperx</span></span>
  1671. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">whisperx 路徑:</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> whisperx</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">__file__</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 應為 /content/whisperx/__init__.py</span></span>
  1672. <span class="line"></span>
  1673. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> os</span></span>
  1674. <span class="line"></span>
  1675. <span class="line"><span style="color: #D8DEE9FF">file_path </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">/content/whisperx/alignment.py</span><span style="color: #ECEFF4">&#39;</span></span>
  1676. <span class="line"><span style="color: #81A1C1">with</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">open</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">file_path</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">r</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> file</span><span style="color: #ECEFF4">:</span></span>
  1677. <span class="line"><span style="color: #D8DEE9FF">    lines </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> file</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">readlines</span><span style="color: #ECEFF4">()</span></span>
  1678. <span class="line"></span>
  1679. <span class="line"><span style="color: #616E88"># 修復 regular_scores 的縮進</span></span>
  1680. <span class="line"><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> i</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> line </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">enumerate</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">lines</span><span style="color: #ECEFF4">):</span></span>
  1681. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">regular_scores = frame_emission[tokens.clamp(min=0).long()]</span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> line</span><span style="color: #ECEFF4">:</span></span>
  1682. <span class="line"><span style="color: #D8DEE9FF">        lines</span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">    </span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> line</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">lstrip</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 設置為 4 個空格</span></span>
  1683. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">break</span></span>
  1684. <span class="line"></span>
  1685. <span class="line"><span style="color: #616E88"># 寫回文件</span></span>
  1686. <span class="line"><span style="color: #81A1C1">with</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">open</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">file_path</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">w</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> file</span><span style="color: #ECEFF4">:</span></span>
  1687. <span class="line"><span style="color: #D8DEE9FF">    file</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">writelines</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">lines</span><span style="color: #ECEFF4">)</span></span>
  1688. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">已修復 regular_scores 的縮進</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1689. <span class="line"></span>
  1690. <span class="line"><span style="color: #616E88"># 驗證修改</span></span>
  1691. <span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">sed </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">n </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">420,435p</span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">content</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">whisperx</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">alignment</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">py</span></span>
  1692. <span class="line"></span>
  1693. <span class="line"></span></code></pre></div>
  1694.  
  1695.  
  1696.  
  1697. <p></p>
  1698.  
  1699.  
  1700.  
  1701. <h2 class="wp-block-heading">Part 4: 載入函式庫與參數設定</h2>
  1702.  
  1703.  
  1704.  
  1705. <p>這裡沒什麼變,主要改的是 whisperx.DiarizationPipeline 要改成whisperx.diarize.DiarizationPipeline。</p>
  1706.  
  1707.  
  1708.  
  1709. <p>其他維持現狀:</p>
  1710.  
  1711.  
  1712.  
  1713. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>import whisperx
  1714. import torch
  1715. import gc
  1716. import os
  1717.  
  1718. # from faster_whisper import WhisperModel
  1719. from tqdm import tqdm
  1720. import os
  1721. from google.colab import files
  1722. from google.colab import userdata
  1723.  
  1724.  
  1725.  
  1726. model_size = &#8220;large-v2&#8243; # tiny, base, small, medium, large, large-v2, large-v3
  1727. batch_size = 16 # reduce if low on GPU mem
  1728. device=&#8221;cuda&#8221;
  1729.  
  1730. # 設定檔案路徑
  1731. audio_path = &#8220;/content/drive/MyDrive/Colab Notebooks/.mp3&#8221; # 替換成你的檔案名稱
  1732.  
  1733. HF_TOKEN = userdata.get(&#8216;HF_TOKEN&#8217;)
  1734. os.environ[&#8216;HUGGING_FACE_HUB_TOKEN&#8217;] = HF_TOKEN
  1735.  
  1736.  
  1737. # 1. Transcribe with original whisper (batched)
  1738. print(&#8220;正在載入 Whisper 模型&#8230;&#8221;)
  1739. model = whisperx.load_model(model_size, device, compute_type=&#8221;float16&#8243;)
  1740.  
  1741. print(f&#8221;正在載入音訊檔案: {audio_path}&#8221;)
  1742. audio = whisperx.load_audio(audio_path)
  1743.  
  1744. print(&#8220;正在進行轉錄&#8230;&#8221;)
  1745. result = model.transcribe(audio, batch_size=batch_size, chunk_size=6)
  1746. # print( result[&#8220;segments&#8221;]) # before alignment
  1747.  
  1748. # 2. Align whisper output
  1749. print(&#8220;正在載入對齊模型&#8230;&#8221;)
  1750. model_a, metadata = whisperx.load_align_model(language_code=result[&#8220;language&#8221;], device=device)
  1751.  
  1752. aligned_result = whisperx.align(result[&#8220;segments&#8221;], model_a, metadata, audio, device, return_char_alignments=True, interpolate_method=&#8221;linear&#8221;)
  1753.  
  1754.  
  1755. # 3. Assign speaker labels
  1756. print(&#8220;正在載入說話人分割模型&#8230;&#8221;)
  1757. diarize_model = whisperx.diarize.DiarizationPipeline(device=device)
  1758. diarize_segments = diarize_model(audio)
  1759. # add min/max number of speakers if known
  1760. # diarize_segments = diarize_model(audio, min_speakers=1, max_speakers=2)
  1761. # print(diarize_segments)
  1762.  
  1763.  
  1764. print(&#8220;正在將說話人標籤分配給詞語&#8230;&#8221;)
  1765. final_result = whisperx.assign_word_speakers(diarize_segments, aligned_result)
  1766. # print(final_result[&#8220;segments&#8221;]) # segments are now assigned speaker IDs
  1767.  
  1768. print(&#8220;\n&#8212; 最終結果 (片段與說話人) &#8212;&#8220;)
  1769.  
  1770. # for segment in final_result[&#8220;segments&#8221;]:
  1771.    # speaker = segment.get(&#8216;speaker&#8217;, &#8216;未知說話人&#8217;)
  1772.    # start_time = segment[&#8216;start&#8217;]
  1773.    # end_time = segment[&#8216;end&#8217;]
  1774.    # text = segment[&#8216;text&#8217;]
  1775.    # print(f&#8221;[{start_time:.2f}s &#8211; {end_time:.2f}s] {speaker}: {text}&#8221;)
  1776.  
  1777.  
  1778.  
  1779.    # &#8212; 清理記憶體 &#8212;
  1780. #del model, model_a, diarize_model, result, aligned_result, final_result, audio
  1781. gc.collect()
  1782. torch.cuda.empty_cache()
  1783. print(&#8220;\n已清理所有模型和變數的記憶體.&#8221;)
  1784. </textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> whisperx</span></span>
  1785. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> torch</span></span>
  1786. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> gc</span></span>
  1787. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> os</span></span>
  1788. <span class="line"></span>
  1789. <span class="line"><span style="color: #616E88"># from faster_whisper import WhisperModel</span></span>
  1790. <span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> tqdm </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> tqdm</span></span>
  1791. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> os</span></span>
  1792. <span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> google</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">colab </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> files</span></span>
  1793. <span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> google</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">colab </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> userdata</span></span>
  1794. <span class="line"></span>
  1795. <span class="line"></span>
  1796. <span class="line"></span>
  1797. <span class="line"><span style="color: #D8DEE9FF">model_size </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">large-v2</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88"># tiny, base, small, medium, large, large-v2, large-v3</span></span>
  1798. <span class="line"><span style="color: #D8DEE9FF">batch_size </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">16</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88"># reduce if low on GPU mem</span></span>
  1799. <span class="line"><span style="color: #D8DEE9FF">device</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">cuda</span><span style="color: #ECEFF4">&quot;</span></span>
  1800. <span class="line"></span>
  1801. <span class="line"><span style="color: #616E88"># 設定檔案路徑</span></span>
  1802. <span class="line"><span style="color: #D8DEE9FF">audio_path </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/content/drive/MyDrive/Colab Notebooks/.mp3</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88"># 替換成你的檔案名稱</span></span>
  1803. <span class="line"></span>
  1804. <span class="line"><span style="color: #D8DEE9FF">HF_TOKEN </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> userdata</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">HF_TOKEN</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span></span>
  1805. <span class="line"><span style="color: #D8DEE9FF">os</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">environ</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">HUGGING_FACE_HUB_TOKEN</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> HF_TOKEN</span></span>
  1806. <span class="line"></span>
  1807. <span class="line"></span>
  1808. <span class="line"><span style="color: #616E88"># 1. Transcribe with original whisper (batched)</span></span>
  1809. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在載入 Whisper 模型...</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1810. <span class="line"><span style="color: #D8DEE9FF">model </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> whisperx</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">load_model</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">model_size</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> device</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">compute_type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">float16</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1811. <span class="line"></span>
  1812. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;正在載入音訊檔案: </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">audio_path</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1813. <span class="line"><span style="color: #D8DEE9FF">audio </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> whisperx</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">load_audio</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">audio_path</span><span style="color: #ECEFF4">)</span></span>
  1814. <span class="line"></span>
  1815. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在進行轉錄...</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1816. <span class="line"><span style="color: #D8DEE9FF">result </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> model</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">transcribe</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">audio</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">batch_size</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">batch_size</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">chunk_size</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">6</span><span style="color: #ECEFF4">)</span></span>
  1817. <span class="line"><span style="color: #616E88"># print( result[&quot;segments&quot;]) # before alignment</span></span>
  1818. <span class="line"></span>
  1819. <span class="line"><span style="color: #616E88"># 2. Align whisper output</span></span>
  1820. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在載入對齊模型...</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1821. <span class="line"><span style="color: #D8DEE9FF">model_a</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> metadata </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> whisperx</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">load_align_model</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">language_code</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">result</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">language</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">],</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">device</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">device</span><span style="color: #ECEFF4">)</span></span>
  1822. <span class="line"></span>
  1823. <span class="line"><span style="color: #D8DEE9FF">aligned_result </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> whisperx</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">align</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">result</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">segments</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">],</span><span style="color: #D8DEE9FF"> model_a</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> metadata</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> audio</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> device</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">return_char_alignments</span><span style="color: #81A1C1">=True</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">interpolate_method</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">linear</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1824. <span class="line"></span>
  1825. <span class="line"></span>
  1826. <span class="line"><span style="color: #616E88"># 3. Assign speaker labels</span></span>
  1827. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在載入說話人分割模型...</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1828. <span class="line"><span style="color: #D8DEE9FF">diarize_model </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> whisperx</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">diarize</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">DiarizationPipeline</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">device</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">device</span><span style="color: #ECEFF4">)</span></span>
  1829. <span class="line"><span style="color: #D8DEE9FF">diarize_segments </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">diarize_model</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">audio</span><span style="color: #ECEFF4">)</span></span>
  1830. <span class="line"><span style="color: #616E88"># add min/max number of speakers if known</span></span>
  1831. <span class="line"><span style="color: #616E88"># diarize_segments = diarize_model(audio, min_speakers=1, max_speakers=2)</span></span>
  1832. <span class="line"><span style="color: #616E88"># print(diarize_segments)</span></span>
  1833. <span class="line"></span>
  1834. <span class="line"></span>
  1835. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在將說話人標籤分配給詞語...</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1836. <span class="line"><span style="color: #D8DEE9FF">final_result </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> whisperx</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">assign_word_speakers</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">diarize_segments</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> aligned_result</span><span style="color: #ECEFF4">)</span></span>
  1837. <span class="line"><span style="color: #616E88"># print(final_result[&quot;segments&quot;]) # segments are now assigned speaker IDs</span></span>
  1838. <span class="line"></span>
  1839. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #A3BE8C">--- 最終結果 (片段與說話人) ---</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1840. <span class="line"></span>
  1841. <span class="line"><span style="color: #616E88"># for segment in final_result[&quot;segments&quot;]:</span></span>
  1842. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># speaker = segment.get(&#39;speaker&#39;, &#39;未知說話人&#39;)</span></span>
  1843. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># start_time = segment[&#39;start&#39;]</span></span>
  1844. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># end_time = segment[&#39;end&#39;]</span></span>
  1845. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># text = segment[&#39;text&#39;]</span></span>
  1846. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># print(f&quot;[{start_time:.2f}s - {end_time:.2f}s] {speaker}: {text}&quot;)</span></span>
  1847. <span class="line"></span>
  1848. <span class="line"></span>
  1849. <span class="line"></span>
  1850. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># --- 清理記憶體 ---</span></span>
  1851. <span class="line"><span style="color: #616E88">#del model, model_a, diarize_model, result, aligned_result, final_result, audio</span></span>
  1852. <span class="line"><span style="color: #D8DEE9FF">gc</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">collect</span><span style="color: #ECEFF4">()</span></span>
  1853. <span class="line"><span style="color: #D8DEE9FF">torch</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">cuda</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">empty_cache</span><span style="color: #ECEFF4">()</span></span>
  1854. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #A3BE8C">已清理所有模型和變數的記憶體.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  1855. <span class="line"></span></code></pre></div>
  1856.  
  1857.  
  1858.  
  1859. <p></p>
  1860.  
  1861.  
  1862.  
  1863. <h2 class="wp-block-heading">Part 4: 合併同講者詞與 GPT-4 斷句</h2>
  1864.  
  1865.  
  1866.  
  1867. <p>這裡也沒什麼改變,只是把 Chat GPT model 改成新的/較便宜的 gpt-4.1-nano 而已。</p>
  1868.  
  1869.  
  1870.  
  1871. <p>但其實切字部份code還有改善的空間。</p>
  1872.  
  1873.  
  1874.  
  1875. <p></p>
  1876.  
  1877.  
  1878.  
  1879. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>!pip install openai
  1880. print(&#8220;\n&#8212;&#8212;&#8212;&#8212;&#8212; 中文merge 與斷句處理  &#8212;&#8212;&#8212;\n&#8221;)
  1881.  
  1882.  
  1883. import openai
  1884. import time
  1885. import os
  1886.  
  1887.  
  1888. HF_TOKEN = userdata.get(&#8216;OPENAI_API&#8217;)
  1889. os.environ[&#8216;OPENAI_API_KEY&#8217;] = HF_TOKEN
  1890.  
  1891. ##########################################
  1892.  
  1893. # 先把同一個發言者的字合併
  1894.  
  1895.  
  1896. def merge_words_by_speaker(segments):
  1897.    merged = []
  1898.    current = {
  1899.        &#8220;speaker&#8221;: None,
  1900.        &#8220;text&#8221;: &#8220;&#8221;,
  1901.        &#8220;start&#8221;: None,
  1902.        &#8220;end&#8221;: None
  1903.    }
  1904.  
  1905.    pending_unknown = None  # 用來暫存沒有時間的 UNKNOWN 詞
  1906.  
  1907.    for segment in segments:
  1908.        for word in segment.get(&#8220;words&#8221;, []):
  1909.  
  1910.            speaker = word.get(&#8220;speaker&#8221;, &#8220;UNKNOWN&#8221;)
  1911.            word_text = word[&#8220;word&#8221;]
  1912.  
  1913.            # 處理 UNKNOWN 且沒時間標記的詞
  1914.            if speaker == &#8220;UNKNOWN&#8221; and &#8220;start&#8221; not in word and &#8220;end&#8221; not in word:
  1915.                # 當作當前 speaker 的延伸,先暫存
  1916.                current[&#8220;text&#8221;] += word_text
  1917.                pending_unknown = word_text
  1918.                continue
  1919.  
  1920.            # speaker 改變時,儲存上一段
  1921.            if current[&#8220;speaker&#8221;] != speaker:
  1922.                if current[&#8220;text&#8221;]:
  1923.                    merged.append(current)
  1924.  
  1925.                # 如果有 pending_unknown,要接到下一個 speaker 的開頭
  1926.                if pending_unknown:
  1927.                    word_text = pending_unknown + word_text
  1928.                    pending_unknown = None
  1929.  
  1930.                current = {
  1931.                    &#8220;speaker&#8221;: speaker,
  1932.                    &#8220;text&#8221;: word_text,
  1933.                    &#8220;start&#8221;: word.get(&#8220;start&#8221;),
  1934.                    &#8220;end&#8221;: word.get(&#8220;end&#8221;)
  1935.                }
  1936.  
  1937.            else:
  1938.                # 同一位 speaker 的詞
  1939.                pending_unknown = None
  1940.                current[&#8220;text&#8221;] += word_text
  1941.                if &#8220;end&#8221; in word:
  1942.                    current[&#8220;end&#8221;] = word[&#8220;end&#8221;]
  1943.  
  1944.  
  1945.    # 加入最後一段
  1946.    if current[&#8220;text&#8221;]:
  1947.        merged.append(current)
  1948.  
  1949.    return merged
  1950.  
  1951.  
  1952.  
  1953.  
  1954.  
  1955.  
  1956. # 用 GPT-4 做斷句處理
  1957.  
  1958.  
  1959. client = openai.OpenAI()  # 用環境變數設定 OPENAI_API_KEY
  1960.  
  1961. def punctuate_with_gpt(text, model=&#8221;gpt-4.1-nano&#8221;, max_retry=3):
  1962.    prompt = f&#8221;&#8221;&#8221;請幫我將以下沒有標點的中文話語補上合適的標點(例如句號、逗號、問號等),並分成自然語言語句:
  1963.  
  1964. {text}
  1965.  
  1966. 輸出時只需要修正後的文本,不需要其他解釋。&#8221;&#8221;&#8221;
  1967.  
  1968.    for _ in range(max_retry):
  1969.        try:
  1970.            response = client.chat.completions.create(
  1971.                model=model,
  1972.                messages=[{&#8220;role&#8221;: &#8220;user&#8221;, &#8220;content&#8221;: prompt}],
  1973.                temperature=0.3
  1974.            )
  1975.            return response.choices[0].message.content.strip()
  1976.        except Exception as e:
  1977.            print(f&#8221;API error: {e}&#8221;)
  1978.            time.sleep(2)
  1979.    return text
  1980.  
  1981.  
  1982. # 對合併後的結果做 GPT 斷句處理
  1983. def process_segments_with_gpt(merged_results, length_threshold=10):
  1984.    processed = []
  1985.    for segment in merged_results:
  1986.        raw_text = segment[&#8216;text&#8217;]
  1987.        if len(raw_text) >= length_threshold:
  1988.            processed_text = punctuate_with_gpt(raw_text)
  1989.        else:
  1990.            processed_text = raw_text
  1991.  
  1992.        processed.append({
  1993.            &#8220;speaker&#8221;: segment.get(&#8220;speaker&#8221;, &#8220;未知說話人&#8221;),
  1994.            &#8220;start&#8221;: segment.get(&#8220;start&#8221;),
  1995.            &#8220;end&#8221;: segment.get(&#8220;end&#8221;),
  1996.            &#8220;text&#8221;: processed_text
  1997.        })
  1998.    return processed
  1999.  
  2000.  
  2001.  
  2002. # Step 4: 輸出結果
  2003. def print_segments(segments):
  2004.    for seg in segments:
  2005.        start = seg[&#8220;start&#8221;]
  2006.        end = seg[&#8220;end&#8221;]
  2007.        speaker = seg[&#8220;speaker&#8221;]
  2008.        text = seg[&#8220;text&#8221;]
  2009.        print(f&#8221;[{start:.2f}s &#8211; {end:.2f}s] {speaker}: {text}&#8221;)
  2010.  
  2011.  
  2012.  
  2013.  
  2014.  
  2015.  
  2016.  # 使用方式
  2017.  
  2018. print(&#8220;正在合併同一個發言者的發言&#8230;\n&#8221;)
  2019. merged_results = merge_words_by_speaker(final_result[&#8220;segments&#8221;])
  2020.  
  2021. print(&#8220;正在使用 GPT 作斷句和標點處理…&#8230;\n&#8221;)
  2022. final_sentences = process_segments_with_gpt(merged_results)
  2023.  
  2024. </textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">!</span><span style="color: #D8DEE9FF">pip install openai</span></span>
  2025. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #A3BE8C">--------------- 中文merge 與斷句處理  ---------</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2026. <span class="line"></span>
  2027. <span class="line"></span>
  2028. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> openai</span></span>
  2029. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> time</span></span>
  2030. <span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> os</span></span>
  2031. <span class="line"></span>
  2032. <span class="line"></span>
  2033. <span class="line"><span style="color: #D8DEE9FF">HF_TOKEN </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> userdata</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">OPENAI_API</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">)</span></span>
  2034. <span class="line"><span style="color: #D8DEE9FF">os</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">environ</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">OPENAI_API_KEY</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> HF_TOKEN</span></span>
  2035. <span class="line"></span>
  2036. <span class="line"><span style="color: #616E88">##########################################</span></span>
  2037. <span class="line"></span>
  2038. <span class="line"><span style="color: #616E88"># 先把同一個發言者的字合併</span></span>
  2039. <span class="line"></span>
  2040. <span class="line"></span>
  2041. <span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">merge_words_by_speaker</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">segments</span><span style="color: #ECEFF4">):</span></span>
  2042. <span class="line"><span style="color: #D8DEE9FF">    merged </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[]</span></span>
  2043. <span class="line"><span style="color: #D8DEE9FF">    current </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
  2044. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">None</span><span style="color: #ECEFF4">,</span></span>
  2045. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #ECEFF4">,</span></span>
  2046. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">None</span><span style="color: #ECEFF4">,</span></span>
  2047. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">None</span></span>
  2048. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
  2049. <span class="line"></span>
  2050. <span class="line"><span style="color: #D8DEE9FF">    pending_unknown </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">None</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 用來暫存沒有時間的 UNKNOWN 詞</span></span>
  2051. <span class="line"></span>
  2052. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> segment </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> segments</span><span style="color: #ECEFF4">:</span></span>
  2053. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> word </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> segment</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">words</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[]):</span></span>
  2054. <span class="line"></span>
  2055. <span class="line"><span style="color: #D8DEE9FF">            speaker </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> word</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">UNKNOWN</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2056. <span class="line"><span style="color: #D8DEE9FF">            word_text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> word</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">word</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2057. <span class="line"></span>
  2058. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88"># 處理 UNKNOWN 且沒時間標記的詞</span></span>
  2059. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> speaker </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">UNKNOWN</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">and</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">not</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> word </span><span style="color: #81A1C1">and</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">not</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> word</span><span style="color: #ECEFF4">:</span></span>
  2060. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #616E88"># 當作當前 speaker 的延伸,先暫存</span></span>
  2061. <span class="line"><span style="color: #D8DEE9FF">                current</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> word_text</span></span>
  2062. <span class="line"><span style="color: #D8DEE9FF">                pending_unknown </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> word_text</span></span>
  2063. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">continue</span></span>
  2064. <span class="line"></span>
  2065. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88"># speaker 改變時,儲存上一段</span></span>
  2066. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> current</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> speaker</span><span style="color: #ECEFF4">:</span></span>
  2067. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> current</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]:</span></span>
  2068. <span class="line"><span style="color: #D8DEE9FF">                    merged</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">append</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">current</span><span style="color: #ECEFF4">)</span></span>
  2069. <span class="line"></span>
  2070. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #616E88"># 如果有 pending_unknown,要接到下一個 speaker 的開頭</span></span>
  2071. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> pending_unknown</span><span style="color: #ECEFF4">:</span></span>
  2072. <span class="line"><span style="color: #D8DEE9FF">                    word_text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> pending_unknown </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> word_text</span></span>
  2073. <span class="line"><span style="color: #D8DEE9FF">                    pending_unknown </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">None</span></span>
  2074. <span class="line"></span>
  2075. <span class="line"><span style="color: #D8DEE9FF">                current </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
  2076. <span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> speaker</span><span style="color: #ECEFF4">,</span></span>
  2077. <span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> word_text</span><span style="color: #ECEFF4">,</span></span>
  2078. <span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> word</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">),</span></span>
  2079. <span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> word</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2080. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">}</span></span>
  2081. <span class="line"></span>
  2082. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">else</span><span style="color: #ECEFF4">:</span></span>
  2083. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #616E88"># 同一位 speaker 的詞</span></span>
  2084. <span class="line"><span style="color: #D8DEE9FF">                pending_unknown </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">None</span></span>
  2085. <span class="line"><span style="color: #D8DEE9FF">                current</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> word_text</span></span>
  2086. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> word</span><span style="color: #ECEFF4">:</span></span>
  2087. <span class="line"><span style="color: #D8DEE9FF">                    current</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> word</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2088. <span class="line"></span>
  2089. <span class="line"></span>
  2090. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># 加入最後一段</span></span>
  2091. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> current</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]:</span></span>
  2092. <span class="line"><span style="color: #D8DEE9FF">        merged</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">append</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">current</span><span style="color: #ECEFF4">)</span></span>
  2093. <span class="line"></span>
  2094. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> merged</span></span>
  2095. <span class="line"></span>
  2096. <span class="line"></span>
  2097. <span class="line"></span>
  2098. <span class="line"></span>
  2099. <span class="line"></span>
  2100. <span class="line"></span>
  2101. <span class="line"><span style="color: #616E88"># 用 GPT-4 做斷句處理</span></span>
  2102. <span class="line"></span>
  2103. <span class="line"></span>
  2104. <span class="line"><span style="color: #D8DEE9FF">client </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> openai</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">OpenAI</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 用環境變數設定 OPENAI_API_KEY</span></span>
  2105. <span class="line"></span>
  2106. <span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">punctuate_with_gpt</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">text</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">model</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">gpt-4.1-nano</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">max_retry</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">):</span></span>
  2107. <span class="line"><span style="color: #D8DEE9FF">    prompt </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;&quot;&quot;請幫我將以下沒有標點的中文話語補上合適的標點(例如句號、逗號、問號等),並分成自然語言語句:</span></span>
  2108. <span class="line"></span>
  2109. <span class="line"><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">text</span><span style="color: #EBCB8B">}</span></span>
  2110. <span class="line"></span>
  2111. <span class="line"><span style="color: #A3BE8C">輸出時只需要修正後的文本,不需要其他解釋。&quot;&quot;&quot;</span></span>
  2112. <span class="line"></span>
  2113. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> _ </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">range</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">max_retry</span><span style="color: #ECEFF4">):</span></span>
  2114. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">try</span><span style="color: #ECEFF4">:</span></span>
  2115. <span class="line"><span style="color: #D8DEE9FF">            response </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> client</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">chat</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">completions</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">create</span><span style="color: #ECEFF4">(</span></span>
  2116. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">model</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">model</span><span style="color: #ECEFF4">,</span></span>
  2117. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">messages</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">[{</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">role</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">user</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">content</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> prompt</span><span style="color: #ECEFF4">}],</span></span>
  2118. <span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">temperature</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">0.3</span></span>
  2119. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">)</span></span>
  2120. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> response</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">choices</span><span style="color: #ECEFF4">[</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">].</span><span style="color: #D8DEE9FF">message</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">content</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">strip</span><span style="color: #ECEFF4">()</span></span>
  2121. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">except</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Exception</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> e</span><span style="color: #ECEFF4">:</span></span>
  2122. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;API error: </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">e</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2123. <span class="line"><span style="color: #D8DEE9FF">            time</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">sleep</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">)</span></span>
  2124. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> text</span></span>
  2125. <span class="line"></span>
  2126. <span class="line"></span>
  2127. <span class="line"><span style="color: #616E88"># 對合併後的結果做 GPT 斷句處理</span></span>
  2128. <span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">process_segments_with_gpt</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">merged_results</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length_threshold</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">10</span><span style="color: #ECEFF4">):</span></span>
  2129. <span class="line"><span style="color: #D8DEE9FF">    processed </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[]</span></span>
  2130. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> segment </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> merged_results</span><span style="color: #ECEFF4">:</span></span>
  2131. <span class="line"><span style="color: #D8DEE9FF">        raw_text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> segment</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">]</span></span>
  2132. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">len</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">raw_text</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;=</span><span style="color: #D8DEE9FF"> length_threshold</span><span style="color: #ECEFF4">:</span></span>
  2133. <span class="line"><span style="color: #D8DEE9FF">            processed_text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">punctuate_with_gpt</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">raw_text</span><span style="color: #ECEFF4">)</span></span>
  2134. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">else</span><span style="color: #ECEFF4">:</span></span>
  2135. <span class="line"><span style="color: #D8DEE9FF">            processed_text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> raw_text</span></span>
  2136. <span class="line"></span>
  2137. <span class="line"><span style="color: #D8DEE9FF">        processed</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">append</span><span style="color: #ECEFF4">({</span></span>
  2138. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> segment</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">未知說話人</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">),</span></span>
  2139. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> segment</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">),</span></span>
  2140. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> segment</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">),</span></span>
  2141. <span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> processed_text</span></span>
  2142. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">})</span></span>
  2143. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> processed</span></span>
  2144. <span class="line"></span>
  2145. <span class="line"></span>
  2146. <span class="line"></span>
  2147. <span class="line"><span style="color: #616E88"># Step 4: 輸出結果</span></span>
  2148. <span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">print_segments</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">segments</span><span style="color: #ECEFF4">):</span></span>
  2149. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> seg </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> segments</span><span style="color: #ECEFF4">:</span></span>
  2150. <span class="line"><span style="color: #D8DEE9FF">        start </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2151. <span class="line"><span style="color: #D8DEE9FF">        end </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2152. <span class="line"><span style="color: #D8DEE9FF">        speaker </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2153. <span class="line"><span style="color: #D8DEE9FF">        text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2154. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;[</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">start</span><span style="color: #81A1C1">:.2f</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">s - </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">end</span><span style="color: #81A1C1">:.2f</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">s] </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">speaker</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">: </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">text</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2155. <span class="line"></span>
  2156. <span class="line"></span>
  2157. <span class="line"></span>
  2158. <span class="line"></span>
  2159. <span class="line"></span>
  2160. <span class="line"></span>
  2161. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 使用方式</span></span>
  2162. <span class="line"></span>
  2163. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在合併同一個發言者的發言...</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2164. <span class="line"><span style="color: #D8DEE9FF">merged_results </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">merge_words_by_speaker</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">final_result</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">segments</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">])</span></span>
  2165. <span class="line"></span>
  2166. <span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在使用 GPT 作斷句和標點處理…...</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2167. <span class="line"><span style="color: #D8DEE9FF">final_sentences </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">process_segments_with_gpt</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">merged_results</span><span style="color: #ECEFF4">)</span></span>
  2168. <span class="line"></span>
  2169. <span class="line"></span></code></pre></div>
  2170.  
  2171.  
  2172.  
  2173. <p></p>
  2174.  
  2175.  
  2176.  
  2177. <h2 class="wp-block-heading">Part 6. 輸出與儲存結果</h2>
  2178.  
  2179.  
  2180.  
  2181. <p>這部份也沒什麼改變。</p>
  2182.  
  2183.  
  2184.  
  2185. <p>多產生一個沒有時間碼的版本而已。</p>
  2186.  
  2187.  
  2188.  
  2189. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>print(&#8220;正在輸出結果&#8230;\n&#8221;)
  2190. # print_segments(final_sentences)  # 顯示結果
  2191. # save_segments_to_txt(final_sentences, filename=&#8221;transcription_result.txt&#8221;)  # 儲存結果
  2192.  
  2193. # Step 5: 儲存結果到文字檔
  2194.  
  2195. def format_time(seconds):
  2196.    if seconds is None:
  2197.        return &#8220;??:??:??&#8221;
  2198.    hours = int(seconds // 3600)
  2199.    minutes = int((seconds % 3600) // 60)
  2200.    seconds = int(seconds % 60)
  2201.    return f&#8221;{hours:02}:{minutes:02}:{seconds:02}&#8221;
  2202.  
  2203.  
  2204. # 獲取不帶副檔名的檔案名稱
  2205. filename_orig = os.path.splitext(os.path.basename(audio_path))[0]
  2206. filename_orig = filename_orig + &#8220;.txt&#8221;
  2207. filename2_orig = filename_orig + &#8220;-notimecode.txt&#8221;
  2208.  
  2209. def save_segments_to_txt(segments, filename=filename_orig):
  2210.    with open(filename, &#8220;w&#8221;, encoding=&#8221;utf-8&#8243;) as f:
  2211.        for seg in segments:
  2212.            start = format_time(seg[&#8220;start&#8221;])
  2213.            end = format_time(seg[&#8220;end&#8221;])
  2214.            speaker = seg[&#8220;speaker&#8221;]
  2215.            text = seg[&#8220;text&#8221;]
  2216.            f.write(f&#8221;[{start} &#8211; {end}] {speaker}: {text}\n&#8221;)
  2217.  
  2218.    files.download(f&#8221;{filename}&#8221;)
  2219.    print(f&#8221;儲存成功:{filename}&#8221;)
  2220.  
  2221.  
  2222. def save_segments_to_txt2(segments, filename=filename2_orig):
  2223.    with open(filename, &#8220;w&#8221;, encoding=&#8221;utf-8&#8243;) as f:
  2224.        for seg in segments:
  2225.            start = format_time(seg[&#8220;start&#8221;])
  2226.            end = format_time(seg[&#8220;end&#8221;])
  2227.            speaker = seg[&#8220;speaker&#8221;]
  2228.            text = seg[&#8220;text&#8221;]
  2229.            f.write(f&#8221; {text}&#8221;)
  2230.  
  2231.    files.download(f&#8221;{filename}&#8221;)
  2232.    print(f&#8221;儲存成功:{filename}&#8221;)
  2233.  
  2234.  
  2235. # save_segments_to_txt(final_sentences, filename=&#8221;transcription_result.txt&#8221;)  # 儲存結果
  2236. save_segments_to_txt(final_sentences)  # 儲存結果
  2237. save_segments_to_txt2(final_sentences)  # 儲存結果
  2238.  
  2239.  
  2240. </textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正在輸出結果...</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2241. <span class="line"><span style="color: #616E88"># print_segments(final_sentences)  # 顯示結果</span></span>
  2242. <span class="line"><span style="color: #616E88"># save_segments_to_txt(final_sentences, filename=&quot;transcription_result.txt&quot;)  # 儲存結果</span></span>
  2243. <span class="line"></span>
  2244. <span class="line"><span style="color: #616E88"># Step 5: 儲存結果到文字檔</span></span>
  2245. <span class="line"></span>
  2246. <span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">format_time</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">seconds</span><span style="color: #ECEFF4">):</span></span>
  2247. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> seconds </span><span style="color: #81A1C1">is</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">None</span><span style="color: #ECEFF4">:</span></span>
  2248. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">??:??:??</span><span style="color: #ECEFF4">&quot;</span></span>
  2249. <span class="line"><span style="color: #D8DEE9FF">    hours </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">int</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">seconds </span><span style="color: #81A1C1">//</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3600</span><span style="color: #ECEFF4">)</span></span>
  2250. <span class="line"><span style="color: #D8DEE9FF">    minutes </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">int</span><span style="color: #ECEFF4">((</span><span style="color: #D8DEE9FF">seconds </span><span style="color: #81A1C1">%</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3600</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">//</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">60</span><span style="color: #ECEFF4">)</span></span>
  2251. <span class="line"><span style="color: #D8DEE9FF">    seconds </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">int</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">seconds </span><span style="color: #81A1C1">%</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">60</span><span style="color: #ECEFF4">)</span></span>
  2252. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">hours</span><span style="color: #81A1C1">:02</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">:</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">minutes</span><span style="color: #81A1C1">:02</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">:</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">seconds</span><span style="color: #81A1C1">:02</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span></span>
  2253. <span class="line"></span>
  2254. <span class="line"></span>
  2255. <span class="line"><span style="color: #616E88"># 獲取不帶副檔名的檔案名稱</span></span>
  2256. <span class="line"><span style="color: #D8DEE9FF">filename_orig </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> os</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">path</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">splitext</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">os</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">path</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">basename</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">audio_path</span><span style="color: #ECEFF4">))[</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">]</span></span>
  2257. <span class="line"><span style="color: #D8DEE9FF">filename_orig </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> filename_orig </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">.txt</span><span style="color: #ECEFF4">&quot;</span></span>
  2258. <span class="line"><span style="color: #D8DEE9FF">filename2_orig </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> filename_orig </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">-notimecode.txt</span><span style="color: #ECEFF4">&quot;</span></span>
  2259. <span class="line"></span>
  2260. <span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">save_segments_to_txt</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">segments</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">filename</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">filename_orig</span><span style="color: #ECEFF4">):</span></span>
  2261. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">with</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">open</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">filename</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">w</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">encoding</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">utf-8</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> f</span><span style="color: #ECEFF4">:</span></span>
  2262. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> seg </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> segments</span><span style="color: #ECEFF4">:</span></span>
  2263. <span class="line"><span style="color: #D8DEE9FF">            start </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">format_time</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">])</span></span>
  2264. <span class="line"><span style="color: #D8DEE9FF">            end </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">format_time</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">])</span></span>
  2265. <span class="line"><span style="color: #D8DEE9FF">            speaker </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2266. <span class="line"><span style="color: #D8DEE9FF">            text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2267. <span class="line"><span style="color: #D8DEE9FF">            f</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">write</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;[</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">start</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C"> - </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">end</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">] </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">speaker</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">: </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">text</span><span style="color: #EBCB8B">}\n</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2268. <span class="line"></span>
  2269. <span class="line"><span style="color: #D8DEE9FF">    files</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">download</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">filename</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2270. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;儲存成功:</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">filename</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2271. <span class="line"></span>
  2272. <span class="line"></span>
  2273. <span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">save_segments_to_txt2</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">segments</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">filename</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">filename2_orig</span><span style="color: #ECEFF4">):</span></span>
  2274. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">with</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">open</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">filename</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">w</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">encoding</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">utf-8</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> f</span><span style="color: #ECEFF4">:</span></span>
  2275. <span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> seg </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> segments</span><span style="color: #ECEFF4">:</span></span>
  2276. <span class="line"><span style="color: #D8DEE9FF">            start </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">format_time</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">start</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">])</span></span>
  2277. <span class="line"><span style="color: #D8DEE9FF">            end </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">format_time</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">end</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">])</span></span>
  2278. <span class="line"><span style="color: #D8DEE9FF">            speaker </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">speaker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2279. <span class="line"><span style="color: #D8DEE9FF">            text </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seg</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">]</span></span>
  2280. <span class="line"><span style="color: #D8DEE9FF">            f</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">write</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot; </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">text</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2281. <span class="line"></span>
  2282. <span class="line"><span style="color: #D8DEE9FF">    files</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">download</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">filename</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2283. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">&quot;儲存成功:</span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">filename</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">)</span></span>
  2284. <span class="line"></span>
  2285. <span class="line"></span>
  2286. <span class="line"><span style="color: #616E88"># save_segments_to_txt(final_sentences, filename=&quot;transcription_result.txt&quot;)  # 儲存結果</span></span>
  2287. <span class="line"><span style="color: #88C0D0">save_segments_to_txt</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">final_sentences</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 儲存結果</span></span>
  2288. <span class="line"><span style="color: #88C0D0">save_segments_to_txt2</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">final_sentences</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 儲存結果</span></span>
  2289. <span class="line"></span>
  2290. <span class="line"></span>
  2291. <span class="line"></span></code></pre></div>
  2292.  
  2293.  
  2294.  
  2295. <p></p>
  2296.  
  2297.  
  2298.  
  2299. <p>WhisperX 是一個還在發展進化的專案,不過我現在碰到的問題主要是切字的效果。</p>
  2300.  
  2301.  
  2302.  
  2303. <p>另外判斷speaker 的部份,中文還是會受到音質的影響,體感覺得成功率大概只有8~9成。這部份因為使用的頻率不夠高,後面需要再手動處理過。真的還不到無腦輸出的地步。</p>
  2304.  
  2305.  
  2306.  
  2307. <p></p>
  2308.  
  2309.  
  2310.  
  2311. <p>就將就著用吧!</p>
  2312. ]]></content:encoded>
  2313. <wfw:commentRss>https://blog.serv.idv.tw/2025/06/colab-whisperx-transcript-revised-50619/feed/</wfw:commentRss>
  2314. <slash:comments>1</slash:comments>
  2315. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/04/856050467346607298.jpeg" medium="image"></media:content>
  2316.            <post-id xmlns="com-wordpress:feed-additions:1">8274</post-id> </item>
  2317. <item>
  2318. <title>我的備份SOP (2025版)</title>
  2319. <link>https://blog.serv.idv.tw/2025/06/backup-sop-2025/</link>
  2320. <comments>https://blog.serv.idv.tw/2025/06/backup-sop-2025/#respond</comments>
  2321. <dc:creator><![CDATA[PipperL]]></dc:creator>
  2322. <pubDate>Mon, 16 Jun 2025 09:05:00 +0000</pubDate>
  2323. <category><![CDATA[電腦.網路]]></category>
  2324. <category><![CDATA[backblaze]]></category>
  2325. <category><![CDATA[backup]]></category>
  2326. <category><![CDATA[sop]]></category>
  2327. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8266</guid>
  2328.  
  2329. <description><![CDATA[數位時代下,個人與家庭資料的安全性與完整性日益重要。我在2018年寫過一版當時的備份SOP。7年後,我更新了目 ... <a title="我的備份SOP (2025版)" class="read-more" href="https://blog.serv.idv.tw/2025/06/backup-sop-2025/" aria-label="Read more about 我的備份SOP (2025版)">閱讀全文</a>]]></description>
  2330. <content:encoded><![CDATA[
  2331. <p>數位時代下,個人與家庭資料的安全性與完整性日益重要。我在<a href="https://blog.serv.idv.tw/2018/04/backup-sop-2018/">2018年</a>寫過一版當時的備份SOP。7年後,我更新了目前我所使用的,如何在多裝置、大資料量的家庭環境中,建立一套高效且可靠的備份SOP。如果你的環境比較簡單,可以用下面的簡易版本SOP作備份:</p>
  2332.  
  2333.  
  2334.  
  2335. <ol class="wp-block-list">
  2336. <li><strong>異質備份:以大容量外接硬碟作為資料備份與歸檔的主要媒介。</strong>
  2337. <ul class="wp-block-list">
  2338. <li>將所有日常工作文件、重要家庭照片及影像等「熱資料」定期備份至外接硬碟。</li>
  2339.  
  2340.  
  2341.  
  2342. <li>對於不再頻繁使用但具長期保存價值的「冷資料」(如已完成專案的原始檔、高解析度照片RAW檔),定期將其歸檔/搬移至大容量外接硬碟,以釋放主力設備空間。</li>
  2343. </ul>
  2344. </li>
  2345.  
  2346.  
  2347.  
  2348. <li><strong>異地防護:採用 <a href="https://www.backblaze.com/">Backblaze</a> 進行雲端遠端備份。</strong>
  2349. <ul class="wp-block-list">
  2350. <li>僅依賴本地實體儲存仍不足以抵禦區域性災害(如火災、水患或竊盜)。因此,建議利用如 <a href="https://www.backblaze.com/">Backblaze</a> 這類提供個人電腦無限儲存空間的雲端備份服務,作為異地備份解決方案。</li>
  2351.  
  2352.  
  2353.  
  2354. <li><strong>策略性運用:</strong> 對於儲存於外接硬碟中的歸檔資料,可規劃每半年將該外接硬碟連接至主力電腦數日。此舉將使 Backblaze 偵測到並自動將這些歸檔資料納入遠端備份範圍,以極低的邊際成本實現冷資料的異地防護。</li>
  2355. </ul>
  2356. </li>
  2357. </ol>
  2358.  
  2359.  
  2360.  
  2361. <p>如果你對完整版的備份SOP有興趣,想了解我的心路歷程,或是想知道我怎麼處理較複雜的架構,可以繼續看下去。</p>
  2362.  
  2363.  
  2364.  
  2365. <span id="more-8266"></span>
  2366.  
  2367.  
  2368.  
  2369. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  2370.  
  2371.  
  2372.  
  2373. <p></p>
  2374.  
  2375.  
  2376.  
  2377. <p>距離我上次在部落格<a href="https://blog.serv.idv.tw/2018/04/backup-sop-2018/">分享我的備份策略</a>,已經將近七年。回想2018年,我正好面對<a href="https://www.crashplan.com/">Crashplan</a>終止家用方案的影響,懷著嘗試與摸索的心情,逐步將資料轉移到 Google Drive 的 (無限) 空間中。當時,我測試了一種混合方式:對於「熱檔案」進行自動同步,而「冷檔案」則手動上傳。在那個依賴單一個人電腦、資料量尚可控的時期,這種做法似乎行之有效。</p>
  2378.  
  2379.  
  2380.  
  2381. <p>在科技快速發展的七年間,我的數位裝置和資料存放/流向已經有了巨大的變化。</p>
  2382.  
  2383.  
  2384.  
  2385. <p>過去幾乎所有的資料都會匯集到 PC 上,包括文件、資料、照片、影音。所以備份的話針對主力工作PC 進行備份即可。<br>現在則是分散在各個不同的數位裝置上。以相片為例,用單眼相機或運動相機拍的照片,如過去一樣匯集在PC,但手機拍的已經分散在各自的裝置和對應的cloud service (如 iCloud 跟 Google Photo)。再加上孩子使用的數位裝置。要備份的資料已經分散在各地。</p>
  2386.  
  2387.  
  2388.  
  2389. <p>而PC 也是,七年之後,電腦已經從一台單打獨鬥的PC,擴展成為一台主力工作機、一台孩子遊戲PC、一台MacBook Air,以及三台遠端Linux伺服器組成的「聯合艦隊」。資料量伴隨著兩個孩子的成長、攝影和4K影音的成長,以及歲月的累積,已經成長到TB 這種等級的量。</p>
  2390.  
  2391.  
  2392.  
  2393. <p>還好,我對「資料保存」的思考已由過去的「都備份就對了」逐漸演變為更加細緻的見解:並非所有資料都生而平等。有些是攸關身家性命的每日必需品,而有些則是充滿回憶卻鮮少翻閱的傳家寶。將這些資料統一以同一標準對待,效率低下,同時也是資源浪費。</p>
  2394.  
  2395.  
  2396.  
  2397. <p>於是在2025年初夏,我再次進行了一次全面的備份體系盤點與改革。這篇文章便是我對現行策略的完整紀錄與思考沉澱。希望它不僅能成為未來自己的查核清單,也能為同樣在數位洪流中,為資料安身立命而苦惱的朋友們,提供一些可能的靈感。</p>
  2398.  
  2399.  
  2400.  
  2401. <p></p>
  2402.  
  2403.  
  2404.  
  2405. <h2 class="wp-block-heading">核心理念的演進:思考「備份」與「歸檔」</h2>
  2406.  
  2407.  
  2408.  
  2409. <p>過去,我對資料的態度相對單純:重要的資料就需要備份。然而,時間是最好的過濾器,它能改變資料的「溫度」。例如,半年前精心處理的專案文件、數年前的攝影作品RAW檔,以及剪輯完畢但佔據巨大空間的影片素材,這些資料在創作當下是「熱資料」,但隨著時間推移,這些資料的價值則轉變為「冷資料」,是「或許未來某天會用到,沒事的話就放著,不要輕易刪除」的類型。</p>
  2410.  
  2411.  
  2412.  
  2413. <p>如果將這些低頻率取用、高容量佔用的「冷資料」與日常文件、系統設定等高頻變動的「熱資料」混為一談,並用同樣的方式進行備份,將會面臨一系列棘手問題:日常備份速度將受到嚴重阻礙、主力電腦的儲存空間會迅速被侵蝕,備份成本也隨之上升。</p>
  2414.  
  2415.  
  2416.  
  2417. <p>因此,這個版本的策略核心在於將資料的生命週期管理劃分為兩大體系:</p>
  2418.  
  2419.  
  2420.  
  2421. <ol class="wp-block-list">
  2422. <li><strong>正規備份(Backup):</strong> 此類資料直接關係到我的日常工作與數位生活,一旦遺失會立即造成嚴重影響,因此我必須在最短時間內恢復。它們需要最嚴格、最可靠的保護。對此,我遵循並嚴格執行業界的 <strong>3-2-1 原則</strong>:
  2423. <ul class="wp-block-list">
  2424. <li><strong>三份備份:</strong> 原始檔案外,至少擁有兩份複本。</li>
  2425.  
  2426.  
  2427.  
  2428. <li><strong>兩種不同的儲存媒體:</strong> 一份在內置硬碟,另一份在外接硬碟或其他電腦上。</li>
  2429.  
  2430.  
  2431.  
  2432. <li><strong>一份是異地備份:</strong> 將一份複本存放於與本地不同的地理位置。</li>
  2433. </ul>
  2434. </li>
  2435.  
  2436.  
  2437.  
  2438. <li><strong>儲存歸檔(Archive):</strong> 此類資料的核心目標是「安全地移出主力工作機以釋放空間」及「實現低成本的長期保存」。通常來說,它們是已完成專案的原始檔、照片的RAW檔、影片的母帶等資料。即使這些檔案不幸遺失,雖然令人遺憾,但也只是「遺憾」,不會對當前的生活造成巨大的衝擊。歸檔的目標是保留至少1份資料在外部媒體,不追求同步或3-2-1備份,而是以週期性的方式整理與封存。如果要把資料取回,我可以接受較長的恢復時間,例如數週。</li>
  2439. </ol>
  2440.  
  2441.  
  2442.  
  2443. <p>在過去,我曾使用過所謂的「深儲存歸檔(Deep Archive)」,像是 Amazon的 S3 Glacier。但個人使用,長期存放的支出仍然可觀。2018使用的 google drive,在後來google修改政策後,可用容量大幅減少。後來我也試過像 Microsoft E5 類型的方案,希望能找到近乎零成本的雲端空間來存放那些「此生大概不會再看第二眼但又捨不得刪除」的陳年舊檔。不過,目前這些穩定可靠但又零成本方案已不復存在。因此,我將這個想法擱置,專注於將「備份」與「歸檔」兩個核心體系做到極致。</p>
  2444.  
  2445.  
  2446.  
  2447. <p></p>
  2448.  
  2449.  
  2450.  
  2451. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  2452.  
  2453.  
  2454.  
  2455. <p></p>
  2456.  
  2457.  
  2458.  
  2459. <h2 class="wp-block-heading">正規備份:我的3-2-1法則實踐方案</h2>
  2460.  
  2461.  
  2462.  
  2463. <p>針對我歸類在「正規備份」的資料——例如進行中的專案文件、重要的個人和家庭檔案、Lightroom的編目檔等——我以嚴謹的方式實施3-2-1法則:</p>
  2464.  
  2465.  
  2466.  
  2467. <ul class="wp-block-list">
  2468. <li><strong>第1份(本機備份資料):</strong> 資料的第一份備份檔案存放在本機的備份目錄裡 (過去是本機某個備份硬碟),例如<code>/backup</code>。然後用每月執行的腳本簡化備份流程的操作,只要一鍵就可以把需要備份的資料通通備份集合到備份目錄中。</li>
  2469.  
  2470.  
  2471.  
  2472. <li><strong>第2份(本地異質媒體備份):</strong> 資料的第二份備份存放在本地的第二台PC,那是一台從主力工作機退役,目前作為孩子遊戲或上網的機器。我在上面掛了一顆之前用來備份的硬碟,可以用來作為備份機。並且用腳本定期把主力工作機的 /backup 內容同步到第二台PC 上。因為資料同時存在於兩台物理獨立的電腦硬碟中。這樣子就滿足了「兩種不同媒體」的要求。即便主力工作機遭遇不測(如硬碟損毀),我依然能在備份機上找到一份相對完整的近期備份。</li>
  2473.  
  2474.  
  2475.  
  2476. <li><strong>第3份(異地遠端備份):</strong> 這是抵禦火災、地震等區域性災難的最後防線。在這方面,我使用<a href="https://www.backblaze.com/">Backblaze</a>這個服務,用兩年大概5000元的價格,進行遠端備份的服務。它提供了個人電腦無限儲存空間的服務。安裝客戶端後,它會在系統背景以極低的資源佔用,自動上傳硬碟上我所指定的資料。當有需要回復時,可以把要回復的資料下載回來;如果是大量的資料要回復 (TB 等級的),他們也提供直接把資料裝進硬碟裡,然後快遞到府的服務。這個會比我花數週時間下載來得迅速。</li>
  2477. </ul>
  2478.  
  2479.  
  2480.  
  2481. <p>這個組合拳——本機 + 本地異質 + Backblaze(遠端備份)——構建了一個即時性的、本地恢復速度快且具遠端災備能力的防護網,確保我的核心數位資產安全無虞。</p>
  2482.  
  2483.  
  2484. <div class="wp-block-image">
  2485. <figure class="aligncenter size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/289_1x_shots_so.png?resize=1024%2C576&#038;ssl=1" alt="" class="wp-image-8269" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/289_1x_shots_so.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/289_1x_shots_so.png?resize=400%2C225&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/289_1x_shots_so.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/289_1x_shots_so.png?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>
  2486.  
  2487.  
  2488. <h2 class="wp-block-heading">儲存歸檔:資料的生命週期與封存藝術</h2>
  2489.  
  2490.  
  2491.  
  2492. <p>如果說「正規備份」是為了應對「意外」,那麼「儲存歸檔」就是一門管理數位遺產的藝術。它的處理流程更具週期性與儀式感,目標是在確保安全的同時,將陳年資料優雅地移出主力工作機。同時,也是一種資料斷捨離。(但不是真的捨棄)</p>
  2493.  
  2494.  
  2495.  
  2496. <p>以占用空間最顯著的「照片RAW檔」為例,我的歸檔流程同時也展現了資料由熱到冷的生命階段:</p>
  2497.  
  2498.  
  2499.  
  2500. <ol class="wp-block-list">
  2501. <li><strong>誕生與處理(在工作機):</strong> 完成攝影專案後,RAW檔會進入工作機的對應目錄。在使用JPG檔編修的同時,如果出現不足,就會找出對應的RAW 進行編修與輸出。在這階段,它們是站在JPG 檔後面的第二道防線。</li>
  2502.  
  2503.  
  2504.  
  2505. <li><strong>暫時存放(在工作機):</strong> 照片處理完後,JPG成品輸出,這些佔據大量空間的RAW檔任務便完成。我會將它們整批移至工作機歸檔專用目錄<code>/Archives</code>,並依年份、專案分類。</li>
  2506.  
  2507.  
  2508.  
  2509. <li><strong>首次歸檔(工作機 -&gt; 外接硬碟 + 備份機,半年一次):</strong> 每年6月和12月,我會執行一次大規模的歸檔,將需要歸檔的資料移動到大容量外接硬碟。如果備份機有空間的話,我也會放置一份副本,作為歸檔資料的備份 (但非必要)。</li>
  2510.  
  2511.  
  2512.  
  2513. <li><strong>遠端歸檔(外接硬碟 -&gt; Backblaze,半年一次):</strong> 這是我的歸檔策略中最特殊的環節。因為對大容量外接硬碟的可靠度不是完全放心,所以把資料移動到外接硬碟後,我會將大容量外接硬碟接在主力機上一陣子。讓Backblaze偵測到這些外接硬碟。由於我已經把Backblaze 的資料過期期限提升至1年,所以其實Backblaze 的雲端已經有半年前我上傳的資料。他只需要重新確認資料存在,就可以繼續保存下去。透過這樣看似繞路的操作,我可以用極低的邊際成本實現了歸檔資料的遠端備份。而不需要讓那些歸檔資料佔用主力機的空間,我只需每半年將外接硬碟接在主力機上幾天,確保Backblaze 確認資料的存在,並且繼續保存下去。這是一種非典型的「冷備份」上雲方式,兼顧了成本與效益。至於新歸檔的資料,就要多放幾天,讓backblaze 完成上傳備份的任務。</li>
  2514. </ol>
  2515.  
  2516.  
  2517.  
  2518. <p></p>
  2519.  
  2520.  
  2521.  
  2522. <h2 class="wp-block-heading">特殊資料類型的備份策略:處理那些「例外」</h2>
  2523.  
  2524.  
  2525.  
  2526. <p>在「備份」和「歸檔」的兩大主軸之外,還總有一些「例外」,需要特別處理:</p>
  2527.  
  2528.  
  2529.  
  2530. <ul class="wp-block-list">
  2531. <li><strong>iCloud照片:</strong> 手機是現代人生活紀錄的核心工具,iOS 的照片我會交給 iCloud 來儲存。但 iCloud 與其說備份,不如說是一個同步的雲端。備份的話,我目前是選擇開源工具<a href="https://github.com/icloud-photos-downloader/icloud_photos_downloader">icloudpd</a>。設定每月執行一次增量備份,把 iCloud 照片下載存到工作機的某個資料夾,同樣受到Backblaze的遠端備份保護。</li>
  2532.  
  2533.  
  2534.  
  2535. <li><strong>MacBook資料:</strong> Macbook Air 對我而言,比較像是在外的連網裝置。大部份的資料都在雲端,所以我僅僅使用了 Time Machine 作不定期的備份,將系統備份至一顆1TB的外接SSD。</li>
  2536.  
  2537.  
  2538.  
  2539. <li><strong>Google Photo:</strong> 照片的部份除了 Apple 生態系的 iCloud 外,我也同步放了一份在 Google Photo,同時還加了許多從其他來源上傳的照片。這部份比較像是過去備份機制產生的legacy。但多一份資料,也無傷大雅 (只是沒有整理)。Google Photo 的部份需要購買 Google one 來解決容量不足的問題,另外我也每五年用 google takeout 取出一份,歸檔處理。</li>
  2540.  
  2541.  
  2542.  
  2543. <li><strong>遠端伺服器:</strong> 至於遠端Linux的主機,承載著我的個人網站及一些實驗性服務。我分別為它們寫了備份腳本,可以將網站文件、資料庫及Nginx設定檔打包壓縮。然後再定期用<code>rclone</code> 掛載 Google Drive,手動將備份檔移上雲端。雖然這部分的手動操作不如全自動流程優雅,但它強迫我每個月親自檢查一次伺服器,也算是一種有益的例行檢查。</li>
  2544. </ul>
  2545.  
  2546.  
  2547.  
  2548. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  2549. <p><strong>小叮嚀:</strong></p>
  2550.  
  2551.  
  2552.  
  2553. <p>如果要用 rclone mount 把 google drive 掛上來讀寫時,請記得把每個要上傳的檔案大小控制在 2GB 以下 (我是用split 切成1GB)。</p>
  2554.  
  2555.  
  2556.  
  2557. <p>另外vfs 請愛用 <code>rclone --vfs-cache-mode minimal</code> ,這樣比較不會被 google block/reject。</p>
  2558. </blockquote>
  2559.  
  2560.  
  2561.  
  2562. <p></p>
  2563.  
  2564.  
  2565.  
  2566. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  2567.  
  2568.  
  2569.  
  2570. <p></p>
  2571.  
  2572.  
  2573.  
  2574. <h2 class="wp-block-heading">結語:一場永不結束的數位長征</h2>
  2575.  
  2576.  
  2577.  
  2578. <p>備份從來不是一個可以一勞永逸的專案,它更像一場無止境的數位長征,需持續關注、定期檢視,並隨時準備調整方向。整理自己的數位空間,雖然過程繁瑣,但當你環顧那個井然有序、安全無憂的結果,那份油然而生的成就感,正是對所有努力的最佳報答。</p>
  2579.  
  2580.  
  2581.  
  2582. <p>沒有任何一個備份策略是完美的,隨著時間推移必然會暴露出新的問題。目前的架構雖然穩固,不過跟7年前最大的不同就是…用錢解決。添購大容量的硬碟、Backblaze 的訂閱、google One 的訂閱等等,都是一筆開銷。但我都跟自己說:這不是買硬體,這是買保險,避免未來的後悔。</p>
  2583.  
  2584.  
  2585.  
  2586. <p>從2018年那個將所有希望寄託於Google Drive的單純年代,到2025年這個「備份、歸檔分流,異質/異地備份 + Backblaze遠端」的複雜協同備份體系,我的備份策略無疑變得更加繁複 (還好有腳本),但也因此更為穩固與靈活。</p>
  2587.  
  2588.  
  2589.  
  2590. <p>這份落落長的備份SOP,其實就是我這七年數位生活變化的縮影。 一方面藉由分辨「備份」跟「歸檔」,把數位生活裡累積的巨量資料作初步的斷捨離,一方面也更嚴謹地看待所謂的3-2-1法則。希望我的這些想法,能給同樣在數位汪洋中掙扎的你一點點靈感,讓你也能打造一套專屬自己的備份體系,從此告別資料焦慮,把心力花在更重要的事情上。</p>
  2591. ]]></content:encoded>
  2592. <wfw:commentRss>https://blog.serv.idv.tw/2025/06/backup-sop-2025/feed/</wfw:commentRss>
  2593. <slash:comments>0</slash:comments>
  2594. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2016/02/20607701226_e0b1226cd2_b.jpg" medium="image"></media:content>
  2595.            <post-id xmlns="com-wordpress:feed-additions:1">8266</post-id> </item>
  2596. <item>
  2597. <title>n8n Workflow: 在Karakeep 打星就分享到 Twitter</title>
  2598. <link>https://blog.serv.idv.tw/2025/06/n8n-workflow-karakeep/</link>
  2599. <comments>https://blog.serv.idv.tw/2025/06/n8n-workflow-karakeep/#respond</comments>
  2600. <dc:creator><![CDATA[PipperL]]></dc:creator>
  2601. <pubDate>Mon, 09 Jun 2025 09:05:00 +0000</pubDate>
  2602. <category><![CDATA[電腦.網路]]></category>
  2603. <category><![CDATA[IFTTT]]></category>
  2604. <category><![CDATA[Karakeep]]></category>
  2605. <category><![CDATA[n8n]]></category>
  2606. <category><![CDATA[推文]]></category>
  2607. <category><![CDATA[自動化]]></category>
  2608. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8249</guid>
  2609.  
  2610. <description><![CDATA[上週從Pocket跳船到 Karakeep 之後,由於 IFTTT 不支援 Karakeep,之前 IFTTT ... <a title="n8n Workflow: 在Karakeep 打星就分享到 Twitter" class="read-more" href="https://blog.serv.idv.tw/2025/06/n8n-workflow-karakeep/" aria-label="Read more about n8n Workflow: 在Karakeep 打星就分享到 Twitter">閱讀全文</a>]]></description>
  2611. <content:encoded><![CDATA[
  2612. <p>上週<a href="https://blog.serv.idv.tw/2025/06/from-pocket-to-karakeep/">從Pocket跳船到 Karakeep</a> 之後,由於 IFTTT 不支援 Karakeep,之前 IFTTT 上的「打星就分享到 twitter流程」就沒得用了。</p>
  2613.  
  2614.  
  2615.  
  2616. <p>正好也想用 n8n 玩點花樣,於是就到 <a href="https://n8n.io/">n8n</a> 上試著寫個 workflow 來做這件事。</p>
  2617.  
  2618.  
  2619.  
  2620. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  2621. <p><strong>個人血淚提醒:</strong><br>使用 docker compose down 時千萬不要加 &#8220;- v&#8221; (也就是不要下 docker compose down -v)。<br>一般來說 -v 會讓人想到 &#8211;verbose;但在 docker compose 裡是把已經建好的 volume 移除 (remove),包含之前所有輸入的資料,workflow,以及設定。</p>
  2622.  
  2623.  
  2624.  
  2625. <p>我寫到一半要加個功能,想要rebuild container時,粗心大意直接 copy &amp; paste chatGPT 給的指令,然後兩天的心血就…消失了。後面問 chatGPT 他還理直氣壯說我又沒有說要保存 volume 資料… Orz</p>
  2626. </blockquote>
  2627.  
  2628.  
  2629.  
  2630. <p>以下的內容是先請 AI 分析我寫的 workflow,然後我再補充。<br>這樣產生說明文件的方式真的很快。不過某些我覺得重要的節點(node)還是會被略過。得要手動指定或是手動加入。</p>
  2631.  
  2632.  
  2633.  
  2634. <p></p>
  2635.  
  2636.  
  2637.  
  2638. <p>workflow 拆成兩個部份:</p>
  2639.  
  2640.  
  2641.  
  2642. <ul class="wp-block-list">
  2643. <li><strong>Karakeep_webhook_queue.json</strong>:接收 Karakeep 更新書籤時所送出的 webhook,稍後由 Karakeep_share 批次處理。</li>
  2644.  
  2645.  
  2646.  
  2647. <li><strong>Karakeep_share.json</strong>:把已經打星的書籤分享到 Twitter,並把已經分享過的書籤歸到 &#8220;shared&#8221; 列表中。</li>
  2648. </ul>
  2649.  
  2650.  
  2651.  
  2652. <p>我請AI 從功能、架構與流程、重要節點的設定方式等三個面向進行分析。</p>
  2653.  
  2654.  
  2655.  
  2656. <span id="more-8249"></span>
  2657.  
  2658.  
  2659.  
  2660. <p></p>
  2661.  
  2662.  
  2663.  
  2664. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  2665.  
  2666.  
  2667.  
  2668. <h2 class="wp-block-heading">1. Karakeep_webhook_queue.json</h2>
  2669.  
  2670.  
  2671.  
  2672. <figure class="wp-block-image size-large is-style-default"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/856_1x_shots_so.png?resize=1024%2C576&#038;ssl=1" alt="Karakeep_webhook_queue.json" class="wp-image-8250" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/856_1x_shots_so.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/856_1x_shots_so.png?resize=400%2C225&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/856_1x_shots_so.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/856_1x_shots_so.png?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  2673.  
  2674.  
  2675.  
  2676. <h3 class="wp-block-heading">功能</h3>
  2677.  
  2678.  
  2679.  
  2680. <p><code>Karakeep_webhook_queue.json</code> 是一個專為處理 Karakeep webhook 事件設計的 workflow。其主要目的是接收來自 Karakeep 的 webhook 請求(例如書籤更新事件),將相關數據(如 <code>jobId</code> 和 <code>bookmarkId</code>)緩存到文件中,並在一定時間後觸發另一個 workflow 進行批次處理。這種設計特別適用於應對可能短時間內大量觸發的 webhook 事件,通過緩存避免過載並實現批次處理。</p>
  2681.  
  2682.  
  2683.  
  2684. <h3 class="wp-block-heading">架構與流程簡介</h3>
  2685.  
  2686.  
  2687.  
  2688. <p>這個 workflow 的架構由以下核心節點組成:</p>
  2689.  
  2690.  
  2691.  
  2692. <ul class="wp-block-list">
  2693. <li><strong>Webhook 節點</strong>:作為入口,接收 POST 請求。</li>
  2694.  
  2695.  
  2696.  
  2697. <li><strong>Set 節點</strong>:從請求中提取關鍵數據並格式化。</li>
  2698.  
  2699.  
  2700.  
  2701. <li><strong>Execute Command 節點</strong>:用於文件操作,包括寫入隊列 (queue) 和設置獨占標誌。</li>
  2702.  
  2703.  
  2704.  
  2705. <li><strong>IF 節點</strong>:判斷是否成為處理者。</li>
  2706.  
  2707.  
  2708.  
  2709. <li><strong>Wait 節點</strong>:延遲執行以收集更多事件。</li>
  2710.  
  2711.  
  2712.  
  2713. <li><strong>Execute Workflow 節點</strong>:觸發後續處理。</li>
  2714. </ul>
  2715.  
  2716.  
  2717.  
  2718. <p><strong>流程如下</strong>:</p>
  2719.  
  2720.  
  2721.  
  2722. <ol class="wp-block-list">
  2723. <li>Webhook 節點接收 Karakeep 的 POST 請求。</li>
  2724.  
  2725.  
  2726.  
  2727. <li>Set 節點提取 <code>jobId</code> 和 <code>bookmarkId</code>,生成 JSON 對象。</li>
  2728.  
  2729.  
  2730.  
  2731. <li>Execute Command 節點將數據追加到 <code>/files/karakeep-webhook-queue.txt</code>,使用 <code>flock</code> 避免同時寫入的競爭條件 (race condition)。</li>
  2732.  
  2733.  
  2734.  
  2735. <li>另一個 Execute Command 節點嘗試設置獨占標誌 <code>/files/karakeep-process.flag</code>,檢查是否已有處理者在運行。</li>
  2736.  
  2737.  
  2738.  
  2739. <li>如果成為處理者,Wait 節點等待 10 秒,收集更多 webhook 事件 (當在 Karakeep 使用批次處理時)。</li>
  2740.  
  2741.  
  2742.  
  2743. <li>Execute Workflow 節點觸發 &#8220;<code>Karakeep_share</code>&#8221; 這個 workflow,進行後續的處理。</li>
  2744.  
  2745.  
  2746.  
  2747. <li>最後清除隊列文件和獨占標誌。</li>
  2748. </ol>
  2749.  
  2750.  
  2751.  
  2752. <p></p>
  2753.  
  2754.  
  2755.  
  2756. <h3 class="wp-block-heading">重要節點的設定方式</h3>
  2757.  
  2758.  
  2759.  
  2760. <p>以下說明各重要節點在 n8n 中的具體設定方式:</p>
  2761.  
  2762.  
  2763.  
  2764. <ul class="wp-block-list">
  2765. <li><strong>Webhook 節點</strong>
  2766. <ul class="wp-block-list">
  2767. <li><strong>節點類型</strong>:<code>n8n-nodes-base.webhook</code></li>
  2768.  
  2769.  
  2770.  
  2771. <li><strong>設定步驟</strong>:
  2772. <ol class="wp-block-list">
  2773. <li>在 n8n 介面中添加 Webhook 節點。</li>
  2774.  
  2775.  
  2776.  
  2777. <li>設置 <strong>HTTP Method</strong> 為 <code>POST</code>,用於接收 Karakeep 的 webhook 請求。</li>
  2778.  
  2779.  
  2780.  
  2781. <li>設置 <strong>Path</strong> 為 <code>karakeep-bookmark-update-XXXX</code>,作為此 workflow 的唯一路徑。</li>
  2782.  
  2783.  
  2784.  
  2785. <li>在 <strong>Authentication</strong> 中選擇 <code>Header Auth</code>,並配置自定義憑證(例如 API 密鑰),確保安全性。這裡的 key 要跟 Karakeep 那邊的 webhook 觸發設定一致。</li>
  2786. </ol>
  2787. </li>
  2788.  
  2789.  
  2790.  
  2791. <li><strong>用途</strong>:此節點作為 workflow 的觸發點,接收 Karakeep 請求並傳遞數據給後續節點。</li>
  2792. </ul>
  2793. </li>
  2794.  
  2795.  
  2796.  
  2797. <li><strong>Set 節點</strong>
  2798. <ul class="wp-block-list">
  2799. <li><strong>節點類型</strong>:<code>n8n-nodes-base.set</code></li>
  2800.  
  2801.  
  2802.  
  2803. <li><strong>設定步驟</strong>:
  2804. <ol class="wp-block-list">
  2805. <li>添加 Set 節點並選擇 <strong>Mode</strong> 為 JSON,以手動定義輸出數據。</li>
  2806.  
  2807.  
  2808.  
  2809. <li>在 <strong>JSON Output</strong> 欄位中輸入表達式,例如: <br><code>{"jobid": "{{ $json.body.jobId }}", "bookmarkid": "{{ $json.body.bookmarkId }}", "time": {{ $now }}, "log_str": "{{ $now.toISO() }} - {{ $json.body.jobId }} - {{ $json.body.bookmarkId }}"}</code></li>
  2810.  
  2811.  
  2812.  
  2813. <li>確保表達式正確引用上游 Webhook 節點的輸入數據(如 <code>body.jobId</code>)。</li>
  2814. </ol>
  2815. </li>
  2816.  
  2817.  
  2818.  
  2819. <li><strong>用途</strong>:用於從 webhook 請求中提取並格式化關鍵數據,生成結構化的 JSON 輸出。</li>
  2820. </ul>
  2821. </li>
  2822.  
  2823.  
  2824.  
  2825. <li><strong>Execute Command 節點(寫入隊列)</strong>
  2826. <ul class="wp-block-list">
  2827. <li><strong>節點類型</strong>:<code>n8n-nodes-base.executeCommand</code></li>
  2828.  
  2829.  
  2830.  
  2831. <li><strong>設定步驟</strong>:
  2832. <ol class="wp-block-list">
  2833. <li>在 <strong>Command</strong> 欄位輸入以下 shell 命令: <br><code>echo "{{ $json.log_str }}" | flock -x /files/karakeep-webhook-queue.txt tee -a /files/karakeep-webhook-queue.txt</code></li>
  2834.  
  2835.  
  2836.  
  2837. <li>確保命令中使用 <code>$json.log_str</code> 引用 Set 節點生成的日誌字符串。</li>
  2838. </ol>
  2839. </li>
  2840.  
  2841.  
  2842.  
  2843. <li><strong>用途</strong>:通過 <code>flock</code> 實現文件鎖定,將資料地安全追加到隊列文件中,避免同時寫入問題。</li>
  2844. </ul>
  2845. </li>
  2846.  
  2847.  
  2848.  
  2849. <li><strong>Execute Command 節點(設立獨占標誌)</strong>
  2850. <ul class="wp-block-list">
  2851. <li><strong>節點類型</strong>:<code>n8n-nodes-base.executeCommand</code></li>
  2852.  
  2853.  
  2854.  
  2855. <li><strong>設定步驟</strong>:
  2856. <ol class="wp-block-list">
  2857. <li>在 <strong>Command</strong> 欄位輸入包含檔案檢查與鎖定邏輯的腳本,例如檢查檔案是否存在、過期處理(10 分鐘)並使用 <code>flock</code> 設置標誌。</li>
  2858.  
  2859.  
  2860.  
  2861. <li>確保腳本輸出 &#8220;Success&#8221; 或其他標識,以便後續 IF 節點判斷。</li>
  2862. </ol>
  2863. </li>
  2864.  
  2865.  
  2866.  
  2867. <li><strong>用途</strong>:管理獨占標誌,確保同一時間只有一個 workflow 實例處理隊列。</li>
  2868. </ul>
  2869. </li>
  2870.  
  2871.  
  2872.  
  2873. <li><strong>IF 節點</strong>
  2874. <ul class="wp-block-list">
  2875. <li><strong>節點類型</strong>:<code>n8n-nodes-base.if</code></li>
  2876.  
  2877.  
  2878.  
  2879. <li><strong>設定步驟</strong>:
  2880. <ol class="wp-block-list">
  2881. <li>在 <strong>Conditions</strong> 中添加一個條件:
  2882. <ul class="wp-block-list">
  2883. <li>選擇 <code>$json.stdout</code>(前一節點的輸出)。</li>
  2884.  
  2885.  
  2886.  
  2887. <li>設置操作為 <code>Contains</code>,值為 <code>"Success"</code>。</li>
  2888. </ul>
  2889. </li>
  2890.  
  2891.  
  2892.  
  2893. <li>配置 True 和 False 兩條分支,分別連接後續節點。</li>
  2894. </ol>
  2895. </li>
  2896.  
  2897.  
  2898.  
  2899. <li><strong>用途</strong>:根據獨占標誌設置的結果,決定是否繼續執行處理邏輯。</li>
  2900. </ul>
  2901. </li>
  2902.  
  2903.  
  2904.  
  2905. <li><strong>Wait 節點</strong>
  2906. <ul class="wp-block-list">
  2907. <li><strong>節點類型</strong>:<code>n8n-nodes-base.wait</code></li>
  2908.  
  2909.  
  2910.  
  2911. <li><strong>設定步驟</strong>:
  2912. <ol class="wp-block-list">
  2913. <li>在 <strong>Amount</strong> 欄位設置為 <code>10</code>,單位為 <code>Seconds</code>。</li>
  2914. </ol>
  2915. </li>
  2916.  
  2917.  
  2918.  
  2919. <li><strong>用途</strong>:暫停 10 秒後再繼續,允許收集更多 webhook 事件以進行批次處理。</li>
  2920. </ul>
  2921. </li>
  2922.  
  2923.  
  2924.  
  2925. <li><strong>Execute Workflow 節點</strong>
  2926. <ul class="wp-block-list">
  2927. <li><strong>節點類型</strong>:<code>n8n-nodes-base.executeWorkflow</code></li>
  2928.  
  2929.  
  2930.  
  2931. <li><strong>設定步驟</strong>:
  2932. <ol class="wp-block-list">
  2933. <li>在 <strong>Workflow ID</strong> 欄位選擇目標 workflow 的 ID,例如 (對應 <code>Karakeep_share</code>)。</li>
  2934.  
  2935.  
  2936.  
  2937. <li>啟用 <strong>Wait for Sub-Workflow</strong> 選項,設為 <code>true</code>,確保子流程完成後再繼續。</li>
  2938. </ol>
  2939. </li>
  2940.  
  2941.  
  2942.  
  2943. <li><strong>用途</strong>:觸發另一個 workflow 來處理緩存的隊列數據。</li>
  2944. </ul>
  2945. </li>
  2946. </ul>
  2947.  
  2948.  
  2949.  
  2950. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  2951.  
  2952.  
  2953.  
  2954. <h2 class="wp-block-heading">2. Karakeep_share.json</h2>
  2955.  
  2956.  
  2957.  
  2958. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/305_1x_shots_so.png?resize=1024%2C576&#038;ssl=1" alt="Karakeep_share.json" class="wp-image-8252" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/305_1x_shots_so.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/305_1x_shots_so.png?resize=400%2C225&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/305_1x_shots_so.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/06/305_1x_shots_so.png?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  2959.  
  2960.  
  2961.  
  2962. <h3 class="wp-block-heading">功能</h3>
  2963.  
  2964.  
  2965.  
  2966. <p><code>Karakeep_share.json</code> 的目標是從 Karakeep 獲取標記為收藏的書籤,過濾出鏈接類型書籤,根據其內容(note 或 highlight)生成 Twitter 推文內容,然後通過 IFTTT 的webhook發送推文 (這裡我偷懶了 XD),最後將書籤移動到 &#8220;shared&#8221; 列表。 (記得先在 Karakeep 建好 shared 這個list, 大小寫有分)</p>
  2967.  
  2968.  
  2969.  
  2970. <h3 class="wp-block-heading">架構與流程簡介</h3>
  2971.  
  2972.  
  2973.  
  2974. <p>這個 workflow 的架構包括:</p>
  2975.  
  2976.  
  2977.  
  2978. <ul class="wp-block-list">
  2979. <li><strong>Manual Trigger / Execute Workflow Trigger 節點</strong>:觸發點。</li>
  2980.  
  2981.  
  2982.  
  2983. <li><strong>HTTP Request 節點</strong>:與 Karakeep API 交互。</li>
  2984.  
  2985.  
  2986.  
  2987. <li><strong>Split Out / Filter 節點</strong>:處理書籤數據。</li>
  2988.  
  2989.  
  2990.  
  2991. <li><strong>Set / IF / Code 節點</strong>:生成推文。</li>
  2992.  
  2993.  
  2994.  
  2995. <li><strong>Merge 節點</strong>:合併數據流。</li>
  2996.  
  2997.  
  2998.  
  2999. <li><strong>HTTP Request 節點</strong>:把推文送到 IFTTT 。</li>
  3000. </ul>
  3001.  
  3002.  
  3003.  
  3004. <p><strong>流程如下</strong>:</p>
  3005.  
  3006.  
  3007.  
  3008. <ol class="wp-block-list">
  3009. <li>觸發 workflow。</li>
  3010.  
  3011.  
  3012.  
  3013. <li>HTTP Request 節點查詢收藏書籤。</li>
  3014.  
  3015.  
  3016.  
  3017. <li>Split Out 節點拆分書籤列表。</li>
  3018.  
  3019.  
  3020.  
  3021. <li>Filter 節點篩選鏈接類型書籤。</li>
  3022.  
  3023.  
  3024.  
  3025. <li>Set 節點提取關鍵資料。</li>
  3026.  
  3027.  
  3028.  
  3029. <li>IF 節點檢查是否有 <code>note</code>。</li>
  3030.  
  3031.  
  3032.  
  3033. <li>如果沒有 note,檢查是否有 highlight。若有,取得 highlight 內容。</li>
  3034.  
  3035.  
  3036.  
  3037. <li>如果連 highlight 也沒有,那就是最一般的情況。</li>
  3038.  
  3039.  
  3040.  
  3041. <li>用 Code 節點生成推文。</li>
  3042.  
  3043.  
  3044.  
  3045. <li>用 Merge 節點合併結果。</li>
  3046.  
  3047.  
  3048.  
  3049. <li>移動書籤並發送推文。</li>
  3050. </ol>
  3051.  
  3052.  
  3053.  
  3054. <h3 class="wp-block-heading">重要節點的設定方式</h3>
  3055.  
  3056.  
  3057.  
  3058. <p>以下說明各重要節點在 n8n 中的具體設定方式:</p>
  3059.  
  3060.  
  3061.  
  3062. <ul class="wp-block-list">
  3063. <li><strong>HTTP Request 節點(查詢書籤)</strong>
  3064. <ul class="wp-block-list">
  3065. <li><strong>節點類型</strong>:<code>n8n-nodes-base.httpRequest</code></li>
  3066.  
  3067.  
  3068.  
  3069. <li><strong>設定步驟</strong>:
  3070. <ol class="wp-block-list">
  3071. <li>設置 <strong>URL</strong> 為 <code>https://[karakeep site]/api/v1/bookmarks/search</code>。</li>
  3072.  
  3073.  
  3074.  
  3075. <li>在 <strong>Authentication</strong> 中選擇 <code>Generic Credential Type</code>,並配置 <code>Bearer Auth</code> 憑證。 這裡的 API是要存取 Karakeep API 用的。需要在 Karakeep 的 user -> API 那邊建立並取得 API key。</li>
  3076.  
  3077.  
  3078.  
  3079. <li>在 <strong>Query Parameters</strong> 中添加:
  3080. <ul class="wp-block-list">
  3081. <li><code>q=is:fav -list:shared -list:Personal</code></li>
  3082.  
  3083.  
  3084.  
  3085. <li><code>includeContent=false</code></li>
  3086.  
  3087.  
  3088.  
  3089. <li><code>limit=20</code></li>
  3090. </ul>
  3091. </li>
  3092. </ol>
  3093. </li>
  3094.  
  3095.  
  3096.  
  3097. <li><strong>用途</strong>:從 Karakeep API 獲取符合條件的書籤數據。</li>
  3098. </ul>
  3099. </li>
  3100.  
  3101.  
  3102.  
  3103. <li><strong>Filter 節點</strong>
  3104. <ul class="wp-block-list">
  3105. <li><strong>節點類型</strong>:<code>n8n-nodes-base.filter</code></li>
  3106.  
  3107.  
  3108.  
  3109. <li><strong>設定步驟</strong>:
  3110. <ol class="wp-block-list">
  3111. <li>在 <strong>Conditions</strong> 中設置條件:
  3112. <ul class="wp-block-list">
  3113. <li><code>$json.content.type</code> 等於 <code>"link"</code>。</li>
  3114. </ul>
  3115. </li>
  3116. </ol>
  3117. </li>
  3118.  
  3119.  
  3120.  
  3121. <li><strong>用途</strong>:篩選出鏈接類型的書籤,過濾掉其他類型。</li>
  3122. </ul>
  3123. </li>
  3124.  
  3125.  
  3126.  
  3127. <li><strong>Set 節點</strong>
  3128. <ul class="wp-block-list">
  3129. <li><strong>節點類型</strong>:<code>n8n-nodes-base.set</code></li>
  3130.  
  3131.  
  3132.  
  3133. <li><strong>設定步驟</strong>:
  3134. <ol class="wp-block-list">
  3135. <li>在 <strong>Assignments</strong> 中定義多個字段,例如:
  3136. <ul class="wp-block-list">
  3137. <li><code>id</code>:<code>{{ $json.id }}</code></li>
  3138.  
  3139.  
  3140.  
  3141. <li><code>note</code>:<code>{{ $json.note }}</code></li>
  3142.  
  3143.  
  3144.  
  3145. <li><code>content.url</code>:<code>{{ $json.content.url }}</code></li>
  3146. </ul>
  3147. </li>
  3148. </ol>
  3149. </li>
  3150.  
  3151.  
  3152.  
  3153. <li><strong>用途</strong>:提取要分享的書籤內容資料。</li>
  3154. </ul>
  3155. </li>
  3156.  
  3157.  
  3158.  
  3159. <li><strong>IF 節點(檢查 note)</strong>
  3160. <ul class="wp-block-list">
  3161. <li><strong>節點類型</strong>:<code>n8n-nodes-base.if</code></li>
  3162.  
  3163.  
  3164.  
  3165. <li><strong>設定步驟</strong>:
  3166. <ol class="wp-block-list">
  3167. <li>在 <strong>Conditions</strong> 中設置:
  3168. <ul class="wp-block-list">
  3169. <li><code>$json.note</code> 不為空(<code>Not Empty</code>)。</li>
  3170. </ul>
  3171. </li>
  3172.  
  3173.  
  3174.  
  3175. <li>配置 True 和 False 分支。</li>
  3176. </ol>
  3177. </li>
  3178.  
  3179.  
  3180.  
  3181. <li><strong>用途</strong>:判斷書籤是否有 note,決定推文生成方式。</li>
  3182. </ul>
  3183. </li>
  3184.  
  3185.  
  3186.  
  3187. <li><strong>HTTP Request 節點(取得Highlight)</strong>
  3188. <ul class="wp-block-list">
  3189. <li><strong>節點類型</strong>:<code>n8n-nodes-base.httpRequest</code></li>
  3190.  
  3191.  
  3192.  
  3193. <li><strong>設定步驟</strong>:
  3194. <ol class="wp-block-list">
  3195. <li>設置 <strong>URL</strong> 為 <code>https://[karakeep site]/api/v1/bookmarks/{{ $json.id }}/highlights。</code></li>
  3196.  
  3197.  
  3198.  
  3199. <li>在 <strong>Authentication</strong> 中選擇 <code>Generic Credential Type</code>,並配置 <code>Bearer Auth</code> 憑證。</li>
  3200.  
  3201.  
  3202.  
  3203. <li>在 <strong>Query Parameters</strong> 中添加:
  3204. <ul class="wp-block-list">
  3205. <li><code>bookmarkId={{ $json.id }}</code></li>
  3206. </ul>
  3207. </li>
  3208. </ol>
  3209. </li>
  3210.  
  3211.  
  3212.  
  3213. <li><strong>用途</strong>:從 Karakeep API 獲取符合條件的書籤數據。</li>
  3214. </ul>
  3215. </li>
  3216.  
  3217.  
  3218.  
  3219. <li><strong>IF 節點(檢查 highlight)</strong>
  3220. <ul class="wp-block-list">
  3221. <li><strong>節點類型</strong>:<code>n8n-nodes-base.if</code></li>
  3222.  
  3223.  
  3224.  
  3225. <li><strong>設定步驟</strong>:
  3226. <ol class="wp-block-list">
  3227. <li>在 <strong>Conditions</strong> 中設置:
  3228. <ul class="wp-block-list">
  3229. <li><code>{{ $json.highlights[0].bookmarkId }}</code> 不為空(<code>Not Empty</code>)。</li>
  3230. </ul>
  3231. </li>
  3232.  
  3233.  
  3234.  
  3235. <li>配置 True 和 False 分支。</li>
  3236. </ol>
  3237. </li>
  3238.  
  3239.  
  3240.  
  3241. <li><strong>用途</strong>:判斷書籤是否有 highlight,決定推文生成方式。</li>
  3242. </ul>
  3243. </li>
  3244.  
  3245.  
  3246.  
  3247. <li><strong>Code 節點(生成推文)</strong>
  3248. <ul class="wp-block-list">
  3249. <li><strong>節點類型</strong>:<code>n8n-nodes-base.code</code></li>
  3250.  
  3251.  
  3252.  
  3253. <li><strong>設定步驟</strong>:
  3254. <ol class="wp-block-list">
  3255. <li>添加 Code 節點並設置 <strong>Mode</strong> 為 <code>Run Once for Each Item</code>。</li>
  3256.  
  3257.  
  3258.  
  3259. <li>在 <strong>JS Code</strong> 欄位輸入自定義 JavaScript,例如計算字數、裁剪內容並生成推文。</li>
  3260. </ol>
  3261. </li>
  3262.  
  3263.  
  3264.  
  3265. <li><strong>用途</strong>:處理數據並生成符合 Twitter 要求的推文內容。</li>
  3266. </ul>
  3267. </li>
  3268. </ul>
  3269.  
  3270.  
  3271.  
  3272. <p>以下是我用來產生推文的程式碼,內容有點雜亂,供參考參考。</p>
  3273.  
  3274.  
  3275.  
  3276. <p><br><strong>for note:</strong></p>
  3277.  
  3278.  
  3279.  
  3280. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="    // 計算字數的函式
  3281. function countTwitterLength(text) {
  3282.  const URL_LENGTH = 23;
  3283.  let length = 0;
  3284.  
  3285.  for (let char of text) {
  3286.    length += char.charCodeAt(0) <= 0x7f ? 1 : 2;
  3287.  }
  3288.  
  3289.  return length;
  3290. }
  3291.  
  3292. const URL_LENGTH = 23;
  3293. const maxLen = 280;
  3294. const ending = '…';
  3295.  
  3296. // note 推文格式: Note (無引號)  [讀] 標題 網址
  3297. // 計算標題長度
  3298. const tweet_title = '[讀] ' + $json.content.title;
  3299. const tweet_title_length = countTwitterLength(tweet_title);
  3300. $json.tweet_title = tweet_title;
  3301. $json.tweet_title_length = tweet_title_length;
  3302.  
  3303. const max_note_length = maxLen - URL_LENGTH - tweet_title_length - 3 - 3; // ... + 換行
  3304.  
  3305. // 裁剪 note 部份
  3306. let result = '';
  3307. let length = 0;
  3308. const tweet_note_orig = $json.note;
  3309. const tweet_note_orig_length = countTwitterLength(tweet_note_orig);
  3310.  
  3311. for (let i = 0; i < tweet_note_orig.length; i++) {
  3312.  const char = tweet_note_orig[i];
  3313.  const charLen = char.charCodeAt(0) <= 0x7f ? 1 : 2;
  3314.  
  3315.  // 若加上這個字已經超過 maxLen,就停止,並補尾碼
  3316.  if (length + charLen &gt; max_note_length) {
  3317.    result += ending;
  3318.    break;
  3319.  }
  3320.  
  3321.  result += char;
  3322.  length += charLen;
  3323. }
  3324.  
  3325. $json.tweet_note = result;
  3326.  
  3327. // 加回 標題 和 網址(每個網址算固定 23 字元)
  3328.  
  3329. $json.tweet_msg = $json.tweet_note + &quot;\n\n&quot; + $json.tweet_title + &quot;\n&quot; + $json.content.url;
  3330.  
  3331.  
  3332. return $json;" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 計算字數的函式</span></span>
  3333. <span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">countTwitterLength</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">text</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
  3334. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">URL_LENGTH</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">23</span><span style="color: #81A1C1">;</span></span>
  3335. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
  3336. <span class="line"></span>
  3337. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">of</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">text</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
  3338. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">charCodeAt</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x7f</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #81A1C1">;</span></span>
  3339. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
  3340. <span class="line"></span>
  3341. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #81A1C1">;</span></span>
  3342. <span class="line"><span style="color: #ECEFF4">}</span></span>
  3343. <span class="line"></span>
  3344. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">URL_LENGTH</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">23</span><span style="color: #81A1C1">;</span></span>
  3345. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">maxLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">280</span><span style="color: #81A1C1">;</span></span>
  3346. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ending</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">…</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
  3347. <span class="line"></span>
  3348. <span class="line"><span style="color: #616E88">// note 推文格式: Note (無引號)  [讀] 標題 網址</span></span>
  3349. <span class="line"><span style="color: #616E88">// 計算標題長度</span></span>
  3350. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">[讀] </span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">content</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">title</span><span style="color: #81A1C1">;</span></span>
  3351. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">countTwitterLength</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
  3352. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title</span><span style="color: #81A1C1">;</span></span>
  3353. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #81A1C1">;</span></span>
  3354. <span class="line"></span>
  3355. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">max_note_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">maxLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">URL_LENGTH</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ... + 換行</span></span>
  3356. <span class="line"></span>
  3357. <span class="line"><span style="color: #616E88">// 裁剪 note 部份 </span></span>
  3358. <span class="line"><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;&#39;</span><span style="color: #81A1C1">;</span></span>
  3359. <span class="line"><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
  3360. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">note</span><span style="color: #81A1C1">;</span></span>
  3361. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">countTwitterLength</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
  3362. <span class="line"></span>
  3363. <span class="line"><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">length</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
  3364. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #D8DEE9FF">[</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span></span>
  3365. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">charLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">charCodeAt</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x7f</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #81A1C1">;</span></span>
  3366. <span class="line"></span>
  3367. <span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// 若加上這個字已經超過 maxLen,就停止,並補尾碼</span></span>
  3368. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">charLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">max_note_length</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
  3369. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ending</span><span style="color: #81A1C1">;</span></span>
  3370. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">break;</span></span>
  3371. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
  3372. <span class="line"></span>
  3373. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #81A1C1">;</span></span>
  3374. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">charLen</span><span style="color: #81A1C1">;</span></span>
  3375. <span class="line"><span style="color: #ECEFF4">}</span></span>
  3376. <span class="line"></span>
  3377. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_note</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #81A1C1">;</span></span>
  3378. <span class="line"></span>
  3379. <span class="line"><span style="color: #616E88">// 加回 標題 和 網址(每個網址算固定 23 字元)</span></span>
  3380. <span class="line"></span>
  3381. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_msg</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_note</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">content</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">url</span><span style="color: #81A1C1">;</span></span>
  3382. <span class="line"></span>
  3383. <span class="line"></span>
  3384. <span class="line"><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #81A1C1">;</span></span></code></pre></div>
  3385.  
  3386.  
  3387.  
  3388. <p></p>
  3389.  
  3390.  
  3391.  
  3392. <p><strong>for hightlight:</strong></p>
  3393.  
  3394.  
  3395.  
  3396. <div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="// 計算字數的函式
  3397. function countTwitterLength(text) {
  3398.  const URL_LENGTH = 23;
  3399.  let length = 0;
  3400.  
  3401.  for (let char of text) {
  3402.    length += char.charCodeAt(0) <= 0x7f ? 1 : 2;
  3403.  }
  3404.  
  3405.  return length;
  3406. }
  3407.  
  3408. const URL_LENGTH = 23;
  3409. const maxLen = 280;
  3410. const ending = '…';
  3411.  
  3412. // note 推文格式: Note (無引號)  [讀] 標題 網址
  3413. // 計算標題長度
  3414. const tweet_title = '[讀] ' + $json.content.title;
  3415. const tweet_title_length = countTwitterLength(tweet_title);
  3416. $json.tweet_title = tweet_title;
  3417. $json.tweet_title_length = tweet_title_length;
  3418.  
  3419. const max_note_length = maxLen - URL_LENGTH - tweet_title_length - 3 - 3 - 2; // ... + 換行 + 引號
  3420.  
  3421. // 裁剪 highlight 部份
  3422. let result = '';
  3423. let length = 0;
  3424. const tweet_note_orig = $json.highlights[0].text
  3425. const tweet_note_orig_length = countTwitterLength(tweet_note_orig);
  3426.  
  3427. for (let i = 0; i < tweet_note_orig.length; i++) {
  3428.  const char = tweet_note_orig[i];
  3429.  const charLen = char.charCodeAt(0) <= 0x7f ? 1 : 2;
  3430.  
  3431.  // 若加上這個字已經超過 maxLen,就停止,並補尾碼
  3432.  if (length + charLen &gt; max_note_length) {
  3433.    result += ending;
  3434.    break;
  3435.  }
  3436.  
  3437.  result += char;
  3438.  length += charLen;
  3439. }
  3440.  
  3441. $json.tweet_highlight = result;
  3442.  
  3443. // 加回 標題 和 網址(每個網址算固定 23 字元)
  3444.  
  3445. $json.tweet_msg = '&quot;' + $json.tweet_highlight + '&quot;' + &quot;\n\n&quot; + $json.tweet_title + &quot;\n&quot; + $json.content.url;
  3446.  
  3447.  
  3448. return $json;" style="color:#d8dee9ff;display:none" aria-label="複製" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// 計算字數的函式</span></span>
  3449. <span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">countTwitterLength</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">text</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
  3450. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">URL_LENGTH</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">23</span><span style="color: #81A1C1">;</span></span>
  3451. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
  3452. <span class="line"></span>
  3453. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">of</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">text</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
  3454. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">charCodeAt</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x7f</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #81A1C1">;</span></span>
  3455. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
  3456. <span class="line"></span>
  3457. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #81A1C1">;</span></span>
  3458. <span class="line"><span style="color: #ECEFF4">}</span></span>
  3459. <span class="line"></span>
  3460. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">URL_LENGTH</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">23</span><span style="color: #81A1C1">;</span></span>
  3461. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">maxLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">280</span><span style="color: #81A1C1">;</span></span>
  3462. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ending</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">…</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
  3463. <span class="line"></span>
  3464. <span class="line"><span style="color: #616E88">// note 推文格式: Note (無引號)  [讀] 標題 網址</span></span>
  3465. <span class="line"><span style="color: #616E88">// 計算標題長度</span></span>
  3466. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">[讀] </span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">content</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">title</span><span style="color: #81A1C1">;</span></span>
  3467. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">countTwitterLength</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
  3468. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title</span><span style="color: #81A1C1">;</span></span>
  3469. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #81A1C1">;</span></span>
  3470. <span class="line"></span>
  3471. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">max_note_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">maxLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">URL_LENGTH</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_title_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ... + 換行 + 引號</span></span>
  3472. <span class="line"></span>
  3473. <span class="line"><span style="color: #616E88">// 裁剪 highlight 部份 </span></span>
  3474. <span class="line"><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;&#39;</span><span style="color: #81A1C1">;</span></span>
  3475. <span class="line"><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
  3476. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">highlights</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">]</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">text</span></span>
  3477. <span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig_length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">countTwitterLength</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
  3478. <span class="line"></span>
  3479. <span class="line"><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">length</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
  3480. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tweet_note_orig</span><span style="color: #D8DEE9FF">[</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span></span>
  3481. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">charLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">charCodeAt</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x7f</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #81A1C1">;</span></span>
  3482. <span class="line"></span>
  3483. <span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// 若加上這個字已經超過 maxLen,就停止,並補尾碼</span></span>
  3484. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">charLen</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">max_note_length</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
  3485. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ending</span><span style="color: #81A1C1">;</span></span>
  3486. <span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">break;</span></span>
  3487. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
  3488. <span class="line"></span>
  3489. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #81A1C1">;</span></span>
  3490. <span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">charLen</span><span style="color: #81A1C1">;</span></span>
  3491. <span class="line"><span style="color: #ECEFF4">}</span></span>
  3492. <span class="line"></span>
  3493. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_highlight</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #81A1C1">;</span></span>
  3494. <span class="line"></span>
  3495. <span class="line"><span style="color: #616E88">// 加回 標題 和 網址(每個網址算固定 23 字元)</span></span>
  3496. <span class="line"></span>
  3497. <span class="line"><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_msg</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_highlight</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">&quot;</span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tweet_title</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">content</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">url</span><span style="color: #81A1C1">;</span></span>
  3498. <span class="line"></span>
  3499. <span class="line"></span>
  3500. <span class="line"><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">$json</span><span style="color: #81A1C1">;</span></span></code></pre></div>
  3501.  
  3502.  
  3503.  
  3504. <ul class="wp-block-list">
  3505. <li><strong>Merge 節點</strong>
  3506. <ul class="wp-block-list">
  3507. <li><strong>節點類型</strong>:<code>n8n-nodes-base.merge</code></li>
  3508.  
  3509.  
  3510.  
  3511. <li><strong>設定步驟</strong>:
  3512. <ol class="wp-block-list">
  3513. <li>添加 Merge 節點。</li>
  3514.  
  3515.  
  3516.  
  3517. <li>設置 <strong>Mode</strong> 為 <code>Combine</code>,並選擇 <strong>Combine By</strong> 為 <code>Position</code>。</li>
  3518. </ol>
  3519. </li>
  3520.  
  3521.  
  3522.  
  3523. <li><strong>用途</strong>:合併來自不同分支的數據流,準備後續處理。</li>
  3524. </ul>
  3525. </li>
  3526. </ul>
  3527.  
  3528.  
  3529.  
  3530. <ul class="wp-block-list">
  3531. <li><strong>HTTP Request 節點(get lists)</strong>
  3532. <ul class="wp-block-list">
  3533. <li><strong>節點類型</strong>:n8n-nodes-base.httpRequest</li>
  3534.  
  3535.  
  3536.  
  3537. <li><strong>設定步驟</strong>:
  3538. <ol class="wp-block-list">
  3539. <li>設置 <strong>URL</strong> 為 https://[karakeep site]/api/v1/lists。</li>
  3540.  
  3541.  
  3542.  
  3543. <li>在 <strong>Authentication</strong> 中選擇 Generic Credential Type,並配置 Bearer Auth 憑證。</li>
  3544.  
  3545.  
  3546.  
  3547. <li>啟用 <strong>Execute Once</strong> 選項設為 true,以避免對每條書籤數據重複請求。我只是要取得 &#8220;shared&#8221; 這個 list 的 id 而已…</li>
  3548.  
  3549.  
  3550.  
  3551. <li>可選:在 <strong>Response Format</strong> 中選擇 JSON,確保返回數據易於解析。</li>
  3552. </ol>
  3553. </li>
  3554.  
  3555.  
  3556.  
  3557. <li><strong>用途</strong>:從 Karakeep API 獲取所有列表的數據,包括 &#8220;shared&#8221; 列表的 ID,用於後續將書籤移動到指定列表。</li>
  3558. </ul>
  3559. </li>
  3560.  
  3561.  
  3562.  
  3563. <li><strong>HTTP Request 節點(send to buffer via IFTTT)</strong>
  3564. <ul class="wp-block-list">
  3565. <li><strong>節點類型</strong>:n8n-nodes-base.httpRequest</li>
  3566.  
  3567.  
  3568.  
  3569. <li><strong>設定步驟</strong>:
  3570. <ol class="wp-block-list">
  3571. <li>設置 <strong>Method</strong> 為 POST。</li>
  3572.  
  3573.  
  3574.  
  3575. <li>設置 <strong>URL</strong> 為 IFTTT 的 webhook URL,例如 https://maker.ifttt.com/trigger/[IFTTT webhook trigger]/with/key/[IFTTT_webhook_key]。</li>
  3576.  
  3577.  
  3578.  
  3579. <li>在 <strong>Body Parameters</strong> 中添加:
  3580. <ul class="wp-block-list">
  3581. <li>名稱:value1,值:{{ $json.tweet_msg }}(引用生成的推文內容)。</li>
  3582. </ul>
  3583. </li>
  3584.  
  3585.  
  3586.  
  3587. <li>在 <strong>Options</strong> 中啟用 <strong>Send Body</strong> 並選擇 JSON 格式。</li>
  3588. </ol>
  3589. </li>
  3590.  
  3591.  
  3592.  
  3593. <li><strong>用途</strong>:通過 IFTTT 的 webhook 將生成的推文內容發送到 Buffer,進而在 Twitter 上發布。</li>
  3594. </ul>
  3595. </li>
  3596.  
  3597.  
  3598.  
  3599. <li><strong>HTTP Request 節點(move to shared list)</strong>
  3600. <ul class="wp-block-list">
  3601. <li><strong>節點類型</strong>:n8n-nodes-base.httpRequest</li>
  3602.  
  3603.  
  3604.  
  3605. <li><strong>設定步驟</strong>:
  3606. <ol class="wp-block-list">
  3607. <li>設置 <strong>Method</strong> 為 PUT。</li>
  3608.  
  3609.  
  3610.  
  3611. <li>設置 <strong>URL</strong> 為 https://[karakppe site]/api/v1/lists/{{ $json.list_id }}/bookmarks/{{ $json.id }},其中 list_id 從 get lists 節點獲取,id 為書籤 ID。</li>
  3612.  
  3613.  
  3614.  
  3615. <li>在 <strong>Authentication</strong> 中選擇 Generic Credential Type,並配置 Bearer Auth 憑證。</li>
  3616.  
  3617.  
  3618.  
  3619. <li>啟用 <strong>Never Error</strong> 選項設為 true,以避免因 API 錯誤中斷 workflow。</li>
  3620. </ol>
  3621. </li>
  3622.  
  3623.  
  3624.  
  3625. <li><strong>用途</strong>:將已分享的書籤移動到 &#8220;shared&#8221; 列表,標記其完成狀態。</li>
  3626. </ul>
  3627. </li>
  3628. </ul>
  3629.  
  3630.  
  3631.  
  3632. <p></p>
  3633.  
  3634.  
  3635.  
  3636. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  3637.  
  3638.  
  3639.  
  3640. <h2 class="wp-block-heading">Future Work:</h2>
  3641.  
  3642.  
  3643.  
  3644. <p>之後還有一些 future work 可以做,像是:</p>
  3645.  
  3646.  
  3647.  
  3648. <ul class="wp-block-list">
  3649. <li>不要透過 IFTTT 去發推文,直接從 n8n 去呼叫 twitter API。</li>
  3650.  
  3651.  
  3652.  
  3653. <li>在 n8n 中加上類似 <a href="https://buffer.com/">buffer.app</a> 定時發文的功能。</li>
  3654.  
  3655.  
  3656.  
  3657. <li>較長的文字不要裁剪,改用回覆的方式支援長文。</li>
  3658.  
  3659.  
  3660.  
  3661. <li>Thread 發文支援</li>
  3662.  
  3663.  
  3664.  
  3665. <li>&#8230;</li>
  3666. </ul>
  3667.  
  3668.  
  3669.  
  3670. <p></p>
  3671.  
  3672.  
  3673.  
  3674. <p>這些就以後有空再實作練習囉。</p>
  3675.  
  3676.  
  3677.  
  3678. <p></p>
  3679.  
  3680.  
  3681.  
  3682. <p></p>
  3683. ]]></content:encoded>
  3684. <wfw:commentRss>https://blog.serv.idv.tw/2025/06/n8n-workflow-karakeep/feed/</wfw:commentRss>
  3685. <slash:comments>0</slash:comments>
  3686. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/06/871916494223592855.png" medium="image"></media:content>
  3687.            <post-id xmlns="com-wordpress:feed-additions:1">8249</post-id> </item>
  3688. <item>
  3689. <title>從 pocket 跳船到 Karakeep</title>
  3690. <link>https://blog.serv.idv.tw/2025/06/from-pocket-to-karakeep/</link>
  3691. <comments>https://blog.serv.idv.tw/2025/06/from-pocket-to-karakeep/#comments</comments>
  3692. <dc:creator><![CDATA[PipperL]]></dc:creator>
  3693. <pubDate>Mon, 02 Jun 2025 09:05:00 +0000</pubDate>
  3694. <category><![CDATA[電腦.網路]]></category>
  3695. <category><![CDATA[GTD]]></category>
  3696. <category><![CDATA[IFTTT]]></category>
  3697. <category><![CDATA[Karakeep]]></category>
  3698. <category><![CDATA[Pocket]]></category>
  3699. <category><![CDATA[self-hosted]]></category>
  3700. <category><![CDATA[simplenote]]></category>
  3701. <category><![CDATA[網路服務]]></category>
  3702. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8238</guid>
  3703.  
  3704. <description><![CDATA[從 gslin 那邊看到 Pocket 要收攤的消息:《 Pocket 總算要關掉了… 》Pocket 這種「 ... <a title="從 pocket 跳船到 Karakeep" class="read-more" href="https://blog.serv.idv.tw/2025/06/from-pocket-to-karakeep/" aria-label="Read more about 從 pocket 跳船到 Karakeep">閱讀全文</a>]]></description>
  3705. <content:encoded><![CDATA[
  3706. <p>從 gslin 那邊看到 Pocket 要收攤的消息:《 <a href="https://blog.gslin.org/archives/2025/05/23/12409/pocket-%e7%b8%bd%e7%ae%97%e8%a6%81%e9%97%9c%e6%8e%89%e4%ba%86/">Pocket 總算要關掉了…</a> 》<br>Pocket 這種「稍後閱讀 (Read it Later)」的工具,在我 GTD 的流程裡扮演了一個很重要的角色。<br>需要閱讀的東西,用方便的小工具 (早期是 bookmarklet,現在是 iOS的 share 跟 browser 的 extension) 丟進去 pool 裡,讀完的 archive 起來。 早期還會想要分類下 tag,但後來實在太麻煩,而且全文搜尋太好用,就不下 tag 或分類了。</p>
  3707.  
  3708.  
  3709.  
  3710. <p>我記得早期我是用 <a href="https://www.instapaper.com/">Instapaper</a> 的,(可能是) 2014年初轉到 <a href="https://getpocket.com">Pocket</a>。<br>當 Mozilla 買下 Pocket,我也沒什麼在意。頂多是後來帳號整合在一塊,登入的時候,要想一下用哪個密碼 (其實也不用記,有自動填入)。</p>
  3711.  
  3712.  
  3713.  
  3714. <p>之後就一直留在 Pocket 沒移動過。一直到 <a href="https://getpocket.com/farewell">Mozilla 決定關掉這個服務</a>為止,我才驚醒:哇!工作流程要被影響了!</p>
  3715.  
  3716.  
  3717.  
  3718. <p>即使現在有那麼多 AI powered,跟桌面程式深度整合的「資訊整合/閱讀」服務,我還是用著古老的 Pocket 跟 Simplenote。一個負責連結,一個負責文字、其他、和初步整理。深度的整理現在是在 Obsidian 上進行,閱讀後的發佈和分享則是交給 blog / twitter / thread 等。閱讀網路文章時,如果覺得適合分享,又不需要(或不適合)打太多心得,早期我用小海的 twitthat,後來就把 Pocket 打星的文章經過 IFTTT串到 twitter上。這麼做,已經很多年了。</p>
  3719.  
  3720.  
  3721.  
  3722. <p>但事情來了,就要面對。<br>於是這一週就花了兩天處理跳船的事情。<br>處理的同時,也在擔心 <a href="https://en.wikipedia.org/wiki/Simplenote">Simplenote</a> 的狀況:跟 Pocket 一樣,被大型服務 (Automattic,就是Wordpress的那家公司)併購後,Simplenote 的開發一直…處於放生的狀態。雖然說服務只要穩定就好,不一定要一直疊加功能上去,但 Simplenote 的狀況比 Pocket 更悲戚一些:沒有穩定的付費模式,<strong>本來開放的 API 陸續收回 (雖然某程度上還有辦法用),第三方的工具一直隕落,也一直缺乏和其他服務的串接 (沒有太多自動化的機會),也沒有針對AI 世代有什麼明顯的回應</strong>。</p>
  3723.  
  3724.  
  3725.  
  3726. <p>簡單來說,就是一個放著 run,燒不了太多錢,但也沒有花心力維護的服務。</p>
  3727.  
  3728.  
  3729.  
  3730. <p>但他還是我用過最「方便」,最順手,也留在我GTD 工具清單最久的工具之一。</p>
  3731.  
  3732.  
  3733.  
  3734. <p>這樣一個服務,要是某天 Automatic 把它關掉,我應該會哀嚎得更大聲。</p>
  3735.  
  3736.  
  3737.  
  3738. <p>好了,扯遠了。</p>
  3739.  
  3740.  
  3741.  
  3742. <p>回到 Pocket 跳船。</p>
  3743.  
  3744.  
  3745.  
  3746. <span id="more-8238"></span>
  3747.  
  3748.  
  3749.  
  3750. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  3751.  
  3752.  
  3753.  
  3754. <h2 class="wp-block-heading" id="-96bc1a07-8896-4717-aca8-9e77b880a518">選擇</h2>
  3755.  
  3756.  
  3757.  
  3758. <p>在找了幾個相類似的服務,包括公開服務的網站 跟 self-hosted (自托管)的選項後。最後我決定先試 <a href="https://karakeep.app/">Karakeep</a> 這個可以自托管的服務,然後把工具架在自己的伺服器上。</p>
  3759.  
  3760.  
  3761.  
  3762. <p>以下是我評估過的服務:</p>
  3763.  
  3764.  
  3765.  
  3766. <p></p>
  3767.  
  3768.  
  3769.  
  3770. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  3771. <h3 class="wp-block-heading">公開服務</h3>
  3772.  
  3773.  
  3774.  
  3775. <ul class="wp-block-list">
  3776. <li>Raindrop.io — All-in-one bookmark manager<br><a href="https://raindrop.io/">https://raindrop.io/</a></li>
  3777. </ul>
  3778.  
  3779.  
  3780.  
  3781. <h3 class="wp-block-heading">self-hosted (自託管)</h3>
  3782.  
  3783.  
  3784.  
  3785. <ul class="wp-block-list">
  3786. <li>Karakeep <br><a href="https://karakeep.app/">https://karakeep.app/</a></li>
  3787. </ul>
  3788.  
  3789.  
  3790.  
  3791. <ul class="wp-block-list">
  3792. <li>wallabag: a self hostable application for saving web pages<br><a href="https://wallabag.org/">https://wallabag.org/</a></li>
  3793. </ul>
  3794.  
  3795.  
  3796.  
  3797. <ul class="wp-block-list">
  3798. <li>go-shiori/shiori: Simple bookmark manager built with Go<br><a href="https://github.com/go-shiori/shiori">https://github.com/go-shiori/shiori</a></li>
  3799. </ul>
  3800.  
  3801.  
  3802.  
  3803. <ul class="wp-block-list">
  3804. <li>Readeck<br><a href="https://readeck.org/en/">https://readeck.org/en/</a></li>
  3805. </ul>
  3806. </blockquote>
  3807.  
  3808.  
  3809.  
  3810. <p>我會選擇 <a href="https://karakeep.app/">Karakeep</a>,最主要的原因有兩個:</p>
  3811.  
  3812.  
  3813.  
  3814. <ol class="wp-block-list">
  3815. <li>除了 Instapaper 外,現在其他的服務我都沒有把握不會在接下來的十年內消失。</li>
  3816.  
  3817.  
  3818.  
  3819. <li>我希望用 AI 來協助處理,而 AI 產生 tag、全文搜尋、支援 <a href="https://www.ithome.com.tw/news/169035">MCP</a> 等,聽起來很吸引人。</li>
  3820. </ol>
  3821.  
  3822.  
  3823.  
  3824. <p></p>
  3825.  
  3826.  
  3827.  
  3828. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  3829.  
  3830.  
  3831.  
  3832. <h2 class="wp-block-heading" id="-35f21c8b-75be-4cfe-ba60-22f4e56c2e8a">安裝</h2>
  3833.  
  3834.  
  3835.  
  3836. <p>現在的軟體安裝,有了 Docker 之後真的很方便。<br>下載 docker-compose.yml 後,把 .env 設好,nginx 的reverse proxy 設一設,避開會衝突的port。機器很順利就run起來了。</p>
  3837.  
  3838.  
  3839.  
  3840. <p>可以設定的東西不多,先初步玩一下發現沒什麼大問題,就準備把資料從 pocket 搬過來了。</p>
  3841.  
  3842.  
  3843.  
  3844. <p>Pocket 有支援 export 功能,匯出的 .csv Karakeep 也可以匯入。</p>
  3845.  
  3846.  
  3847.  
  3848. <p>嗯…從2014 到現在…13000筆書籤。不知道我的小機器吃不吃得下。</p>
  3849.  
  3850.  
  3851.  
  3852. <p>跑了兩天,終於重新 index、抓內容和離線頁面、請 AI tag 完成。還好機器撐住了,沒掛掉。</p>
  3853.  
  3854.  
  3855.  
  3856. <p>一些統計數字如下:</p>
  3857.  
  3858.  
  3859.  
  3860. <ul class="wp-block-list">
  3861. <li>13000 筆書籤 ,其中 2285筆 (占17.45%) 現在已經消失,無法再連得到。部份是Google feedproxy 的連結 (又是該死的 google)</li>
  3862.  
  3863.  
  3864.  
  3865. <li>下載下來的網頁文字、banner 圖檔、和頁面存檔 (snapshot) 占了 4.79GB 的資源。</li>
  3866.  
  3867.  
  3868.  
  3869. <li>Pocket 資料裡的歸檔狀態 (Archived) 沒有過來,導致我必須想辦法把 12900 筆資料設為歸檔。在寫程式用API處理、使用 CLI 處理、以及手動歸檔 (有批次編輯)這三種選項中,我選擇了… 第三種 人工。</li>
  3870.  
  3871.  
  3872.  
  3873. <li>AI 產生 tag 消耗了 8鎂 的 OpenAI credit。</li>
  3874. </ul>
  3875.  
  3876.  
  3877.  
  3878. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  3879. <p><strong>Update 2025/6/8:</strong><br>v0.25.0 已經支援把 Pocket 的歸檔狀態 (Archived) 一併帶入。但我沒有試過。只是根據 release note 所言。  </p>
  3880. </blockquote>
  3881.  
  3882.  
  3883.  
  3884. <p>目前手動的書籤管理 (新增/編輯)已經轉到 Karakeep 上作業了。加書籤的速度跟 Pocket 一樣快,但是AI 處理跟 index 需要時間,所以出現在首頁的時間會需要 30秒左右。</p>
  3885.  
  3886.  
  3887.  
  3888. <p>再觀察看看,真的受不了,再看看如何改善。</p>
  3889.  
  3890.  
  3891.  
  3892. <p></p>
  3893.  
  3894.  
  3895.  
  3896. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  3897.  
  3898.  
  3899.  
  3900. <h2 class="wp-block-heading" id="-be20d2d9-f8d4-4df6-aa55-8434d31c7cfb">還需改善的地方</h2>
  3901.  
  3902.  
  3903.  
  3904. <p></p>
  3905.  
  3906.  
  3907.  
  3908. <h3 class="wp-block-heading" id="-7a37529c-7775-487c-a3bd-ca143fee6701">書籤進系統後,處理的速度不夠快</h3>
  3909.  
  3910.  
  3911.  
  3912. <p>因為要讓 AI 處理過書籤,抓取內容,再讓內建的 Meilisearch index,感覺出現在首頁的速度還是有點慢 (30s 左右),目前還在勉強接受的範圍。</p>
  3913.  
  3914.  
  3915.  
  3916. <p>因為在我 GTD 的流程裡面,新增書籤是 Capture 資訊進 InBox,跟後續的 Clarify/Organize 是在不同階段處理的事。所以我有多的時間讓系統去處理。</p>
  3917.  
  3918.  
  3919.  
  3920. <p></p>
  3921.  
  3922.  
  3923.  
  3924. <h3 class="wp-block-heading" id="-65cbe4c6-45b8-4814-8db8-96b882dc8ebf">半自動化/自動化流程還需要重新打造。</h3>
  3925.  
  3926.  
  3927.  
  3928. <p>主要是因為 IFTTT 不支援 Kerakeep。之前的自動發佈流程就失效了。<br>但正好拿來作為我練習 n8n 的作業之一。</p>
  3929.  
  3930.  
  3931.  
  3932. <p></p>
  3933.  
  3934.  
  3935.  
  3936. <h3 class="wp-block-heading" id="-0a83b561-5a98-4876-8367-81accf929ff4">沒有夠強大的瀏覽器擴充工具</h3>
  3937.  
  3938.  
  3939.  
  3940. <p>自從發現 <a href="https://inmypocketaddon.com/">In-My-Pocket</a> 這個 firefox 的擴充之後,我就把Pocket官方的擴充工具給丟了。甚至連官方的首頁都很少上去。</p>
  3941.  
  3942.  
  3943.  
  3944. <p>現在 Karakeep 的的瀏覽器工具加書籤很順,但也才僅止而已。要閱讀等還是要去首頁。閱讀/打星/歸檔還是沒有那麼流暢。</p>
  3945.  
  3946.  
  3947.  
  3948. <p>我看 In-My-Pocket 的作者也在<a href="https://github.com/pabuisson/in-my-pocket/issues/4">煩惱未來的路怎麼走</a>。我想,就讓子彈飛一會兒吧。</p>
  3949.  
  3950.  
  3951.  
  3952. <p></p>
  3953.  
  3954.  
  3955.  
  3956. <h3 class="wp-block-heading" id="-884eb4e0-aae8-413b-997b-10dde8ea5084">資源占的硬碟空間有點多</h3>
  3957.  
  3958.  
  3959.  
  3960. <p>13000則書籤,即使包括文字,應該不會占太多空間。但實務上占了4.8 GB的空間。初步分析了一下,主要是他抓下來的網頁 banner 並不會處理,就直接存進去。對某些網站一張4K尺寸 PNG 的banner,占了11MB 也照存不誤。累積下來當然很可觀。</p>
  3961.  
  3962.  
  3963.  
  3964. <p>看了一下 Karakeep 的資料架構,之後應該可以把這些圖檔取出來處理成尺寸較小、壓縮率較高 (例如 Jpegli 或是WebP) 的檔案再存回去。這就等有空再處理,反正目前還有空間。</p>
  3965.  
  3966.  
  3967.  
  3968. <p></p>
  3969.  
  3970.  
  3971.  
  3972. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  3973.  
  3974.  
  3975.  
  3976. <h2 class="wp-block-heading" id="-e2719c0e-4008-44b4-aac3-765f6cbf9b50">未來潛力</h2>
  3977.  
  3978.  
  3979.  
  3980. <p></p>
  3981.  
  3982.  
  3983.  
  3984. <p>目前除了手動切換到 Karakeep 使用一陣子,看看有沒有什麼致命問題外。<br>有空的時間會先花時間打造輪子,回到之前習慣的工作流程模式。順便升級一下成自己之前想要,但受限於 Pocket 跟 IFTTT 而無法實現的工作流。</p>
  3985.  
  3986.  
  3987.  
  3988. <p>之後如果不分心的話,會想把這13000筆資料,請AI幫忙,整合進我在思考時的架構之中。畢竟這些文章我當年都有讀過,只是忘了。 XD 怎麼做還不清楚,但可能用 MCP 去 refer 吧。</p>
  3989.  
  3990.  
  3991.  
  3992. <p></p>
  3993.  
  3994.  
  3995.  
  3996. <p>還是希望不要再跳船了,都一把老骨頭了…</p>
  3997.  
  3998.  
  3999.  
  4000. <p></p>
  4001.  
  4002.  
  4003.  
  4004. <p></p>
  4005.  
  4006.  
  4007.  
  4008. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  4009. ]]></content:encoded>
  4010. <wfw:commentRss>https://blog.serv.idv.tw/2025/06/from-pocket-to-karakeep/feed/</wfw:commentRss>
  4011. <slash:comments>2</slash:comments>
  4012. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/05/截圖-2025-05-31-下午2.46.02-scaled.png" medium="image"></media:content>
  4013.            <post-id xmlns="com-wordpress:feed-additions:1">8238</post-id> </item>
  4014. <item>
  4015. <title>白沙屯媽祖進香 &#8211; 其他心得</title>
  4016. <link>https://blog.serv.idv.tw/2025/05/pilgrimage-other-thoughts/</link>
  4017. <comments>https://blog.serv.idv.tw/2025/05/pilgrimage-other-thoughts/#respond</comments>
  4018. <dc:creator><![CDATA[PipperL]]></dc:creator>
  4019. <pubDate>Fri, 23 May 2025 01:47:00 +0000</pubDate>
  4020. <category><![CDATA[白沙屯媽祖徒步進香 (2025)]]></category>
  4021. <category><![CDATA[白沙屯媽祖]]></category>
  4022. <category><![CDATA[裝備]]></category>
  4023. <category><![CDATA[進香]]></category>
  4024. <category><![CDATA[遊覽車]]></category>
  4025. <guid isPermaLink="false">https://blog.serv.idv.tw/?p=8205</guid>
  4026.  
  4027. <description><![CDATA[這應該是我參加 2025 白沙屯媽祖徒步進香的最後一篇。 我把一些比較零碎的想法放在這篇,可能是因為它們的篇幅 ... <a title="白沙屯媽祖進香 &#8211; 其他心得" class="read-more" href="https://blog.serv.idv.tw/2025/05/pilgrimage-other-thoughts/" aria-label="Read more about 白沙屯媽祖進香 &#8211; 其他心得">閱讀全文</a>]]></description>
  4028. <content:encoded><![CDATA[
  4029. <p>這應該是我參加 2025 白沙屯媽祖徒步進香的最後一篇。</p>
  4030.  
  4031.  
  4032.  
  4033. <p>我把一些比較零碎的想法放在這篇,可能是因為它們的篇幅或完整性沒有值得單開一篇來寫,但這些仍然值得被紀錄下來。</p>
  4034.  
  4035.  
  4036.  
  4037. <p>包括有:</p>
  4038.  
  4039.  
  4040.  
  4041. <ul class="wp-block-list">
  4042. <li><strong>裝備回顧</strong>:在進香結束後,回頭來看當初準備的行李和裝備中,哪些符合預期,哪些需要調整。</li>
  4043.  
  4044.  
  4045.  
  4046. <li><strong>遊覽車值不值得</strong>:在個人實際體驗遊覽車之後,和我當初預期不同的地方。如果你是像我一樣類型的香燈腳,請不要選擇坐遊覽車。</li>
  4047.  
  4048.  
  4049.  
  4050. <li><strong>我個人喜歡走的路線</strong>。</li>
  4051.  
  4052.  
  4053.  
  4054. <li><strong>緣未俱足</strong>的部份:還有來年,隨緣。</li>
  4055. </ul>
  4056.  
  4057.  
  4058.  
  4059. <span id="more-8205"></span>
  4060.  
  4061.  
  4062.  
  4063. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  4064.  
  4065.  
  4066.  
  4067. <h2 class="wp-block-heading" id="裝備回顧">裝備回顧</h2>
  4068.  
  4069.  
  4070.  
  4071. <p>在 <a href="https://blog.serv.idv.tw/2025/04/pilgrimage-preparation/">準備</a> 篇,我有提到我準備裝備的方式。實際走一趟回來,大部份的準備是符合預期的:</p>
  4072.  
  4073.  
  4074.  
  4075. <ul class="wp-block-list">
  4076. <li><strong>分類裝進小防水袋</strong>:在下雨天真的安心。唯一的小缺點,就是當好幾包都在行李裡的時候,要馬上找出某一包是有困難的。需要摸一下或是拿出來看一下,沒抽到的話再放回去。</li>
  4077.  
  4078.  
  4079.  
  4080. <li><strong>備用拖鞋(母子鱷魚)</strong>碰到下雨天後真的很好用,晚上在住宿點移動,盥洗或是散步去買個東西也很方便。我這次因為穿的是五指襪,好像也可以穿五指襪後再穿母子鱷魚步行 (但我沒試)。對了,要準備一個鞋袋或是塑膠袋,裝完溼掉的步鞋後,用D型扣掛在背包後。</li>
  4081.  
  4082.  
  4083.  
  4084. <li><strong>雨備包</strong>以這次碰到的雨勢來說,剛剛好。小雨就上背包套,大雨再把輕便雨衣穿上。輕便雨衣還可以拿來鋪在地上當座墊或是床墊。</li>
  4085.  
  4086.  
  4087.  
  4088. <li>食物的部份剛剛好。平常雖然用不到 (都有福食和點心攤),但在應急 (過夜) 時能量棒就給了我許多幫助。</li>
  4089.  
  4090.  
  4091.  
  4092. <li><strong>醫療包</strong>理論上備而不用,我也真的沒用上。全程唯一用上的那把瑞士刀,某天拿來切開包裝 Orz。<br>不過腿受傷時,我倒是有想過要不要吞個止痛藥然後繼續走。但一來我很少這麼做,二來我沒把握會不會傷勢加重,影響回程,所以就沒試了。</li>
  4093. </ul>
  4094.  
  4095.  
  4096.  
  4097. <figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/04/IMG_6201s.jpg?resize=1024%2C768&#038;ssl=1" alt="" class="wp-image-8076" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/04/IMG_6201s.jpg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/04/IMG_6201s.jpg?resize=400%2C300&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/04/IMG_6201s.jpg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/04/IMG_6201s.jpg?w=1920&amp;ssl=1 1920w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  4098.  
  4099.  
  4100.  
  4101. <p>在行程中調整的有:</p>
  4102.  
  4103.  
  4104.  
  4105. <ul class="wp-block-list">
  4106. <li>外套:照片中那件防風外套,在急行軍之後因為沒有晚上穿著的必要,就移至過夜行李,改用一件薄外套。而急行軍其實以今年的天候而言,也用不到那件防風外套/薄外套。但如果那件防風外套有留在隨身背包,我在大安的那一夜應該就不會半夜被冷醒/疑似失溫。</li>
  4107.  
  4108.  
  4109.  
  4110. <li>防曬包裡<strong>大遮陽帽</strong>在去程急行軍後就被我挪到過夜包。當初考量是較大的尺吋可以保護脖子和肩膀不被曬傷。實作上發現官方鴨舌帽加上毛巾披在後腦就有一樣的效果。而言毛巾還可以沾冰水打溼達到更好的消暑效果。移到過夜包後,我的隨身背包又多了一些空間。</li>
  4111.  
  4112.  
  4113.  
  4114. <li><strong>夜行包</strong>裡的東西用上的真的不多,只有夜間警示燈有用到 (掛在背包後),其他包括頭燈都沒用上。主要原因有三:
  4115. <ol class="wp-block-list">
  4116. <li>去程急行軍第一夜 (白沙屯到大安)人很多,基本上沒有用上頭燈的機會。</li>
  4117.  
  4118.  
  4119.  
  4120. <li>去程急行軍第二夜 (麥寮王功鹿港段) 我DNF沒下去走, 後來看其他人的影片,這一段隊伍拉太長,可能會有獨走的情形,加上路燈照明較不足,應該會用得上頭燈。</li>
  4121.  
  4122.  
  4123.  
  4124. <li>回程大多是白天徒步,也沒有用上燈的地方。<br>雖然這次沒用上頭燈,但為了安全起見,我仍然建議要把頭燈放進隨身背包中。</li>
  4125. </ol>
  4126. </li>
  4127.  
  4128.  
  4129.  
  4130. <li><strong>充電包</strong>這次還好有買備用行動電源,但我把其中一顆放在過夜行李。所以實際帶在隨身背包的是兩顆。我正常使用的話,一天大概會用掉一顆10000的行動電源。第二顆除了安心,也讓我在外頭過夜時,不會太擔心第二天的行程。但最麻煩的是 &#8212; 充電。在行程中,不管是急行軍還是平日步行,是找不到什麼機會停下來充電的。以現在的充電速度,每次充電大概要停下來40~60分鐘,其實不是很划算。我後來的作法是:用完的電池放到過夜行李,然後過夜時在住宿點的插頭搭快充頭充&#8211; 這樣一定可充飽。如果住宿點沒有機會,也可以靠遊覽車上的USB 插頭充 (雖然充電速度非常慢),但我早上就下車、傍晚才上車,通常都有足夠的時間充飽。 如果未來要自己露宿,就要好好考慮充電的問題。我在路上有看到帶著太陽能充電板 (我原定要帶的那種) 徒步的人。而這幾天的天氣都比預期的炎熱,我想充電效率應該蠻好的,只是沒機會跟他聊實際使用狀況。可能要找機會自己測試一下。 另外一個意料之外的電力消耗,是手錶。 Garmin 955 開GPS mode 撐不過10hr,不管急行軍或是一般徒步都不夠用。我後來是開 UltraTrac,然後關掉跟手機的連線,有40小時以上的績航力,不過路線精準度就差強人意了。 總之,手錶充電線還是要帶,不然會GG。我也考慮過邊充手錶邊走的選項 (用行充),但這樣應該會有一段的心率資料是缺少的,而且不知道會不會有其他數據受到影響。</li>
  4131.  
  4132.  
  4133.  
  4134. <li>可以準備一個<strong>小提袋 (小的就好) 和 幾個可提的塑膠袋</strong>。小提袋可以手提或是掛在背包前面 (我在背帶上用D型扣掛著,重心在胸到腰間),有結緣、點心、零食、或是福食可以先放入袋中,不用停下來放背包或一直手拿著。小塑膠袋放在小提袋中,吃完的包裝、空瓶等先放到袋裡,等到垃圾回收點可以一次清空。 這個提袋的重量也可以提醒你,是不是已經拿太多了?夠了就好。隨緣。</li>
  4135. </ul>
  4136.  
  4137.  
  4138.  
  4139. <p>整體重量 3.7Kg (不含行程中動態出現在提袋裡的福食和零食),再加上腰帶和胸袋的協助,我覺得背起來不累。如果要再加上露宿的裝備,可能會再加個 __ Kg …吧。這個明年再思考規劃好了。</p>
  4140.  
  4141.  
  4142.  
  4143. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  4144.  
  4145.  
  4146.  
  4147. <h2 class="wp-block-heading" id="遊覽車值不值得報名-乘坐">遊覽車值不值得報名/乘坐?</h2>
  4148.  
  4149.  
  4150.  
  4151. <p>之前我有<a href="https://blog.serv.idv.tw/2025/03/nomad-50-pilgrimage-registration/">提到</a>,自己會報名步行遊覽車的原因:</p>
  4152.  
  4153.  
  4154.  
  4155. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  4156. <p>進香除了全程徒步外,還有所謂的(官方)步行遊覽車。這當然不是指全程坐在遊覽車上,而是在車上有個位子可以放行李,每天晚上還可以幫你訂好住宿 (通常是一定距離廟宇的香客大樓),載你去投宿休息,隔天早上再載你回來繼續徒步。對我而言,這樣子省去了餐風露宿的準備以及行李的負重。對於第一次參加的我,這是一個相對輕鬆的選擇,尤其在面對未知的進香旅程時,能夠有這份保障着實讓我安心不少。</p>
  4157. </blockquote>
  4158.  
  4159.  
  4160.  
  4161. <p>而在報名當天排隊時,前方有一位大姐也跟我分析了遊覽車方案的優缺點:</p>
  4162.  
  4163.  
  4164.  
  4165. <blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  4166. <p>她說遊覽車比較辛苦的,是在一天的步行後,還要再多走一段路去遊覽車停車的地方。通常因為空間的關係,遊覽車會停在外環道附近,這代表要多走30~60分鐘的路程。「已經走了十幾個小時,還要再多走一個小時,真的很累」。另外一個缺點,就是住宿的點車程約1小時,所以休息更晚,出發更早,壓縮到時間。但是好處是不用擔心睡覺和洗澡的地方。</p>
  4167. </blockquote>
  4168.  
  4169.  
  4170.  
  4171. <p>我自己今年搭步行遊覽車的經驗,對於「多走一段路去遊覽車停車的地方」已經有心裡準備,所以並沒有什麼不適應的地方。但我碰到的遊覽車口頭上雖然說「會等到媽祖駐駕後再載我們去住宿點」,但實際上卻會找一些理由提早收人,像是「山路遊覽車開上去會塞太久。」「61平面大塞車,請大家開始往回走」「媽祖繼續走,但是住宿點廟門8點就關,所以要提早走。」…等等。所以對我而言,這次最大的影響,就是因為遊覽車提早收人,而少走了好幾段。</p>
  4172.  
  4173.  
  4174.  
  4175. <p>有機會碰到其他遊覽車的香燈腳,一聊之下,發現其實各遊覽車的作法相差很多,評價也不一。有的就會開上松柏嶺、開到大安去 (當然到住宿點的時間就晚了);有的則是挑近一點但是貴不少的住宿點,像我有碰到跟我抱怨每晚住宿費要1000元的 (但我反而覺得這比駐駕在台中,住宿卻在雲林來得好吧)。</p>
  4176.  
  4177.  
  4178. <div class="wp-block-image">
  4179. <figure class="aligncenter size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6579.jpeg?resize=1024%2C768&#038;ssl=1" alt="" class="wp-image-8177" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6579-scaled.jpeg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6579-scaled.jpeg?resize=400%2C300&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6579-scaled.jpeg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6579-scaled.jpeg?resize=2048%2C1536&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6579-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>
  4180.  
  4181.  
  4182. <p>簡單說,如果你像我一樣有一點認真,想要當個「認真的人」,在可能的情況下儘量步行。那麼步行遊覽車…不適合你。</p>
  4183.  
  4184.  
  4185.  
  4186. <p>如果你想要的行程是坐在遊覽車上,找時間下去跟媽祖走一段,或是一邊吹著遊覽車的冷氣,一邊看媽祖的鑾轎經過,那麼步行遊覽車會是一個不錯的選擇 &#8212; 當然,還要看看你碰到的車掌和司機怎麼掌握停車點和移動的方式。</p>
  4187.  
  4188.  
  4189.  
  4190. <p>以我而言,明年應該不會再報名遊覽車了。這意味著我要克服過夜的問題,以及相對應的行李負重。</p>
  4191.  
  4192.  
  4193.  
  4194. <p>怎麼做? 明年再來想好了…</p>
  4195.  
  4196.  
  4197.  
  4198. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  4199.  
  4200.  
  4201.  
  4202. <h2 class="wp-block-heading" id="我個人喜歡走的路線">我個人喜歡走的路線</h2>
  4203.  
  4204.  
  4205.  
  4206. <p>這是我第一次走,回想起走過的路線,包括省道、快速道路、縣道、沿途經過大城鎮、小城鎮等等。其實很難說自己最愛或是最不喜歡哪一段。</p>
  4207.  
  4208.  
  4209. <div class="wp-block-image">
  4210. <figure class="aligncenter size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="1024" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-1024x1024.jpeg?resize=1024%2C1024&#038;ssl=1" alt="" class="wp-image-8127" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-scaled.jpeg?resize=1024%2C1024&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-scaled.jpeg?resize=400%2C400&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-scaled.jpeg?resize=150%2C150&amp;ssl=1 150w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-scaled.jpeg?resize=1536%2C1536&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-scaled.jpeg?resize=2048%2C2048&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-scaled.jpeg?resize=120%2C120&amp;ssl=1 120w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_6788-edited-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>
  4211.  
  4212.  
  4213. <p>官方說法當然是:「媽祖走哪裡,我就走哪裡。」</p>
  4214.  
  4215.  
  4216.  
  4217. <p>如果以「步行體驗」而言,以下是我的粗淺印象:</p>
  4218.  
  4219.  
  4220.  
  4221. <ul class="wp-block-list">
  4222. <li>走在城鎮和城鎮之間的省道 (台1線),雖然補給很多,但相對而言是比較枯燥的。像從溪湖走到彰化市的這一段,就是沿著省道走呀走呀走…</li>
  4223.  
  4224.  
  4225.  
  4226. <li>走進小鄉鎮或是縣道等,雖然人會塞到滿出來,但保持距離的話,路邊的風景和經過的村里、居民,都讓人比較有「進香」的感覺。像這次走進林內、繞到六房媽那邊,都有這種感覺。</li>
  4227.  
  4228.  
  4229.  
  4230. <li>走在大城鎮裡,有參加嘉年華會的感覺,一直吃一直吃一直喝一直喝。像通霄和北港都給我這種強烈的感覺。</li>
  4231.  
  4232.  
  4233.  
  4234. <li>走在 61下平面道路,或是沿著堤防邊走到和美,真的有「行軍」的感覺。一個車道無限延伸,放眼望去都是橘帽。路邊隨時有人或坐或躺,有的人會願意停下腳步,看看日出的美好風景;有的人願意鋪起墊子,好好睡個一兩個小時。雖說是行軍,雖說目標不變,但每個人的作法還是不一樣的。是不是那麼「認真」,在這個時候,真的需要計較嗎?</li>
  4235. </ul>
  4236.  
  4237.  
  4238.  
  4239. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  4240.  
  4241.  
  4242.  
  4243. <h2 class="wp-block-heading" id="緣未俱足的部份">緣未俱足的部份</h2>
  4244.  
  4245.  
  4246.  
  4247. <p>以下是這次「緣未俱足」的部份,未來有機會,希望能夠結緣:</p>
  4248.  
  4249.  
  4250.  
  4251. <ul class="wp-block-list">
  4252. <li>去程急行軍 DNF</li>
  4253.  
  4254.  
  4255.  
  4256. <li>回程第一天因為腳傷休養沒走,其他天有的受遊覽車影響,提早下馬,沒跟到駐駕地。</li>
  4257.  
  4258.  
  4259.  
  4260. <li>找了孩子要一起體驗半日的步行 (通霄車站段),但因為大雨以及人實在太多,孩子並沒有實際體驗跟媽祖走一段路。他們也沒有太多點心攤和福食結緣的體驗。</li>
  4261.  
  4262.  
  4263.  
  4264. <li>自己事前並沒有準備什麼結緣品,後來都是把其他人跟我結緣的種種紀念品,再次結緣出去給需要的人。</li>
  4265. </ul>
  4266.  
  4267.  
  4268.  
  4269. <p>雖說緣未俱足,但這一次學到的,得到的,媽祖額外給我的,已經很多很多,讓我受用無窮了。<strong>也希望這一系列的文章,可以跟有緣的人結緣</strong>,讓有興趣的人,更了解這個活動,更了解如何準備,以及更了解2025年的這次北港徒步進香,帶給我這個菜鳥香燈腳,什麼樣子的美好體驗。</p>
  4270.  
  4271.  
  4272.  
  4273. <figure class="wp-block-image alignwide size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" src="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_7229.jpeg?resize=1024%2C768&#038;ssl=1" alt="" class="wp-image-8184" srcset="https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_7229-scaled.jpeg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_7229-scaled.jpeg?resize=400%2C300&amp;ssl=1 400w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_7229-scaled.jpeg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_7229-scaled.jpeg?resize=2048%2C1536&amp;ssl=1 2048w, https://i0.wp.com/blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_7229-scaled.jpeg?w=2325&amp;ssl=1 2325w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
  4274.  
  4275.  
  4276.  
  4277. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  4278.  
  4279.  
  4280.  
  4281. <h2 class="wp-block-heading">系列文章閱讀:</h2>
  4282.  
  4283.  
  4284.  
  4285. <p>以下是關於2025我參加白沙屯媽祖進香的系列文章,供您快速一口氣閱讀:</p>
  4286.  
  4287.  
  4288.  
  4289. <ol class="wp-block-list">
  4290. <li><a href="https://blog.serv.idv.tw/2025/03/nomad-50-pilgrimage-registration/">遊民週記 50: 白沙屯媽祖進香 – 報名</a></li>
  4291.  
  4292.  
  4293.  
  4294. <li><a href="https://blog.serv.idv.tw/2025/04/pilgrimage-preparation/">白沙屯媽祖進香 – 準備</a></li>
  4295.  
  4296.  
  4297.  
  4298. <li><a href="https://blog.serv.idv.tw/2025/05/pilgrimage-day1-day2-dnf/">白沙屯媽祖進香 – 去程急行軍</a></li>
  4299.  
  4300.  
  4301.  
  4302. <li><a href="https://blog.serv.idv.tw/2025/05/pilgrimage-step-into-nantou/">白沙屯媽祖進香 – 見證歷史,走入名間</a></li>
  4303.  
  4304.  
  4305.  
  4306. <li><a href="https://blog.serv.idv.tw/2025/05/pilgrimage-magic-experience/">白沙屯媽祖進香 – 台中大安的奇幻旅程</a></li>
  4307.  
  4308.  
  4309.  
  4310. <li><a href="https://blog.serv.idv.tw/2025/05/pilgrimage-types-of-followers/">白沙屯媽祖進香 – 香燈腳眾生百態</a></li>
  4311.  
  4312.  
  4313.  
  4314. <li><a href="https://blog.serv.idv.tw/2025/05/pilgrimage-other-thoughts/">白沙屯媽祖進香 – 其他心得</a></li>
  4315. </ol>
  4316.  
  4317.  
  4318.  
  4319. <p>如果你對這個主題有興趣,可以閱讀<a href="https://blog.serv.idv.tw/category/tour/baishatun-mazu/" target="_blank" rel="noreferrer noopener">同分類的文章</a>,或是點選相關的關鍵字,作更多的閱讀。</p>
  4320.  
  4321.  
  4322.  
  4323. <hr class="wp-block-separator has-alpha-channel-opacity"/>
  4324.  
  4325.  
  4326.  
  4327. <p></p>
  4328. ]]></content:encoded>
  4329. <wfw:commentRss>https://blog.serv.idv.tw/2025/05/pilgrimage-other-thoughts/feed/</wfw:commentRss>
  4330. <slash:comments>0</slash:comments>
  4331. <media:content url="https://blog.serv.idv.tw/wp-content/uploads/2025/05/IMG_7230-scaled.jpeg" medium="image"></media:content>
  4332.            <post-id xmlns="com-wordpress:feed-additions:1">8205</post-id> </item>
  4333. </channel>
  4334. </rss>
  4335.  
  4336. <!--
  4337. Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/
  4338.  
  4339. Page Caching using Disk
  4340. Minified using Disk
  4341. Database Caching using Disk (Request-wide modification query)
  4342.  
  4343. Served from: blog.serv.idv.tw @ 2025-07-19 07:29:34 by W3 Total Cache
  4344. -->
Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda