<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>My Program</title>
	<atom:link href="https://diary.tw/feed" rel="self" type="application/rss+xml" />
	<link>https://diary.tw</link>
	<description>我的程式, 我的觀點</description>
	<lastBuildDate>Tue, 22 Sep 2026 05:40:21 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://diary.tw/files/2020/11/cropped-my-program-icon-32x32.png</url>
	<title>My Program</title>
	<link>https://diary.tw</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">185306385</site>	<item>
		<title>用看看這個不一樣的 AI &#8211; Jev</title>
		<link>https://diary.tw/archives/2791</link>
					<comments>https://diary.tw/archives/2791#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Tue, 22 Sep 2026 05:32:55 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Decision]]></category>
		<category><![CDATA[Jev]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2791</guid>

					<description><![CDATA[之前媒體報導這個新型的 AI模型 Jev, 不會和你長篇大論, 只用來評分與快速回應, 這樣的應用場景更適合在 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>之前媒體報導這個新型的 AI模型 Jev, 不會和你長篇大論, 只用來評分與快速回應, 這樣的應用場景更適合在程式裡使用.</p>
<p>先到官方網站進行註冊 &#8211; <a href="https://typesafe.ai/" target="_blank" rel="noopener">https://typesafe.ai/</a></p>
<p>成功登入後, 介面上有 Agent Setup, 左邊選單有 Playground, Usage, 與 API Key.</p>
<p>可以直接在 Playground 進行測試, 用中文也可以:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
  "7歲小朋友上學問題": {
    "type": "noul",
    "instructions": "台灣的小朋友 7歲要上小學嗎?",
    "criteria": {
      "true": "是",
      "false": "否"
    }
  }
}</pre>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
  "model": "jev-1.13.0",
  "answers": {
    "7歲小朋友上學問題": {
      "type": "noul",
      "noul": 0.89,
      "stats": {}
    }
  },
  "usage": {
    "input_tokens": 299,
    "output_tokens": 28
  },
  "request_id": "playground_10c9754235e9d894eeeab29dc48e3bda170",
  "evaluation_time_ms": 152.92206600133795
}</pre>
<p>看起來可以順利拿到是的答案為 89%.</p>
<p><span id="more-2791"></span></p>
<p>建立 API KEY 後也可以透過 API 來問答:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Content-Type: application/json" \
  -d @- &lt;&lt;'EOF'
  {
    "state": "",
    "model": "jev-latest",
    "questions": {
      "7歲小朋友上學問題": {
        "type": "noul",
        "instructions": "台灣的小朋友 7歲要上小學嗎?",
        "criteria": {
            "true": "是",
            "false": "否"
        }
      }
    }
  }
EOF

{"model":"jev-1.13.0","answers":{"7歲小朋友上學問題":{"type":"noul","noul":0.87}},"usage":{"input_tokens":299,"output_tokens":28}}</pre>
<p>利用 API 也能順利回答出 87%.</p>
<p>更完整的使用可以看看說明 &#8211; <a href="https://docs.typesafe.ai/introduction" target="_blank" rel="noopener">https://docs.typesafe.ai/introduction</a></p>
<p>看起來是不是更適合在程式中使用, 各種不同的業務場景與需要判斷的需求, 在不需要生成文字的應用狀況下, Jev 更適合在流程中使用, 大家可以試看看.</p>
<p>&nbsp;</p>
<p>繼續閱讀:</p>
<p><a href="https://www.bnext.com.tw/article/92319/typesafe-jev-decision-model-explainer" target="_blank" rel="noopener">https://www.bnext.com.tw/article/92319/typesafe-jev-decision-model-explainer</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2791/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2791</post-id>	</item>
		<item>
		<title>如何下載YouTube影片</title>
		<link>https://diary.tw/archives/2770</link>
					<comments>https://diary.tw/archives/2770#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Mon, 31 Aug 2026 13:38:00 +0000</pubDate>
				<category><![CDATA[好用軟體]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[youtube]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2770</guid>

					<description><![CDATA[若在 MacBook 上可以直接使用 yt-dlp 這個開源專案來進行下載影片. https://github [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>若在 MacBook 上可以直接使用 yt-dlp 這個開源專案來進行下載影片.</p>
<p><a href="https://github.com/yt-dlp/yt-dlp" target="_blank" rel="noopener">https://github.com/yt-dlp/yt-dlp</a></p>
<p>安裝方式很簡單, 請直接使用 brew 工具:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">brew install yt-dlp</pre>
<p>建議一併下載 FFmpeg 來提供下載後的影片與聲音的合成:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">brew install ffmpeg</pre>
<p>接下來就可以在命令列進行下載 YouTube 影片, 如影片(其中影片 ID就是後面的那串英數 &#8211; U7mPqycQ0tQ:</p>
<p><iframe title="Girls&amp;apos; Generation 소녀시대 &amp;apos;Gee&amp;apos; MV" width="580" height="326" src="https://www.youtube.com/embed/U7mPqycQ0tQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p><a href="https://www.youtube.com/watch?v=U7mPqycQ0tQ" target="_blank" rel="noopener">https://www.youtube.com/watch?v=U7mPqycQ0tQ</a></p>
<p>我們就使用如下指令:</p>
<p><span id="more-2770"></span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">&gt; yt-dlp U7mPqycQ0tQ
[youtube] Extracting URL: U7mPqycQ0tQ
[youtube] U7mPqycQ0tQ: Downloading webpage
[youtube] U7mPqycQ0tQ: Downloading visionos player API JSON
[youtube] U7mPqycQ0tQ: Downloading m3u8 information
[info] U7mPqycQ0tQ: Downloading 1 format(s): 401+251
[download] Destination: Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f401.mp4
[download] 100% of 353.32MiB in 00:00:24 at 14.27MiB/s
[download] Destination: Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f251.webm
[download] 100% of 3.77MiB in 00:00:00 at 9.37MiB/s
[Merger] Merging formats into "Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].webm"
Deleting original file Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f401.mp4 (pass -k to keep)
Deleting original file Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f251.webm (pass -k to keep)</pre>
<p>就會快速得到一支下載好的 webm 有影片有聲音的檔案 Girls&#8217; Generation 소녀시대 &#8216;Gee&#8217; MV [U7mPqycQ0tQ].webm</p>
<p>若要指定為 mp4 的檔案格式, 可以增加 -S &#8220;ext:mp4:m4a&#8221; 使用如下指令:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">&gt;yt-dlp -S "ext:mp4:m4a" U7mPqycQ0tQ
[youtube] Extracting URL: U7mPqycQ0tQ
[youtube] U7mPqycQ0tQ: Downloading webpage
[youtube] U7mPqycQ0tQ: Downloading visionos player API JSON
[youtube] U7mPqycQ0tQ: Downloading m3u8 information
[info] U7mPqycQ0tQ: Downloading 1 format(s): 401+140
[download] Destination: Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f401.mp4
[download] 100% of 353.32MiB in 00:00:25 at 14.12MiB/s
[download] Destination: Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f140.m4a
[download] 100% of 3.71MiB in 00:00:00 at 13.31MiB/s
[Merger] Merging formats into "Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].mp4"
Deleting original file Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f401.mp4 (pass -k to keep)
Deleting original file Girls' Generation 소녀시대 'Gee' MV [U7mPqycQ0tQ].f140.m4a (pass -k to keep)</pre>
<p>就會得到一個 Girls&#8217; Generation 소녀시대 &#8216;Gee&#8217; MV [U7mPqycQ0tQ].mp4 的檔案.</p>
<p>若是只想要指定的時間區段如 1:10-1:20, 可以增加 &#8211;download-sections &#8220;*01:10-01:20&#8221; 使用如以下指令:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">&gt;yt-dlp --download-sections "*01:10-01:20" -S "ext:mp4:m4a" U7mPqycQ0tQ
....輸出內容較長....略....
</pre>
<p>(上述指令仍會輸出 Girls&#8217; Generation 소녀시대 &#8216;Gee&#8217; MV [U7mPqycQ0tQ].mp4 同之前一樣檔名的檔案, 不過若檔案已存在它就不會再次下載, 記得先將前一次下載的影片改成不一樣的檔名, 再進行這個下載.</p>
<p>這個指定時間區段的內容, 這個對於長影片, 只需要其中一小段內容非常方便, 不需要整個下載就可以快速達成取出其中一段的內容.</p>
<p>快速總結一下:</p>
<ol>
<li>若是下載影片使用 yt-dlp &#8220;影片ID&#8221; &#8211; 會下載最高畫質與使用 webm 的格式輸出</li>
<li>若是需要下載為 mp4 可以使用 yt-dlp -S &#8220;ext:mp4:m4a&#8221; &#8220;影片ID&#8221; &#8211; 則會下載為 mp4 格式</li>
<li>若是需要下載長影片中指定的時間區段, 可以使用 yt-dlp &#8211;download-sections &#8220;*01:10-01:20&#8221; &#8220;影片ID&#8221; &#8211; 即會下載指定時間區間的影片內容</li>
</ol>
<p>快去用看看吧.</p>
<p>繼續閱讀:</p>
<p><a href="https://www.getop.com/group/hui-yuan-fu-wu-qu/discussion/c857ddbc-921e-4a64-b012-859e922d8679" target="_blank" rel="noopener">https://www.getop.com/group/hui-yuan-fu-wu-qu/discussion/c857ddbc-921e-4a64-b012-859e922d8679</a></p>
<p>&nbsp;</p>
<p>補充一下 Windows 版本: [2026/9/15 9:24]</p>
<p>請下載 yt-dlp.exe 與 ffmpeg 工具包 (essential 即可):</p>
<p>yt-dlp.exe: <a href="https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe" target="_blank" rel="noopener">https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe</a></p>
<p>ffmpeg 工具包:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bat">C:\winget install "FFmpeg (Essentials Build)"
`msstore` 來源要求您必須先檢視下列合約，再使用。
Terms of Transaction: https://aka.ms/microsoft-store-terms-of-transaction
來源需要將目前電腦的 2 個字母地理區域傳輸到後端服務，才能正確(例如"US")。

是否同意所有來源合約條款？
[Y] 是  [N] 否: y
找到 FFmpeg (Essentials Build) [Gyan.FFmpeg.Essentials] 版本 9.0.1
此應用程式已由其擁有者授權給您。
Microsoft 不負任何責任，也不會授與協力廠商封裝的任何授權。
正在下載 https://github.com/GyanD/codexffmpeg/releases/download/9.0.1/ffmpeg-9.0.1-essentials_build.zip
  ██████████████████████████████   106 MB /  106 MB
已成功驗證安裝程式雜湊
正在擷取封存...
已成功擷取封存
正在啟動套件安裝...
已修改路徑環境變數；重新啟動命令介面以使用新值。
新增的命令列別名: "ffmpeg"
新增的命令列別名: "ffplay"
新增的命令列別名: "ffprobe"
已成功安裝</pre>
<p>完成後使用如同上面一樣的指令即可順利下載影片囉!</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2770/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2770</post-id>	</item>
		<item>
		<title>Cloudflare提供了免費的網站服務</title>
		<link>https://diary.tw/archives/2760</link>
					<comments>https://diary.tw/archives/2760#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Tue, 18 Aug 2026 15:13:50 +0000</pubDate>
				<category><![CDATA[好用軟體]]></category>
		<category><![CDATA[cloudflare]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[toolbox]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2760</guid>

					<description><![CDATA[Cloudflare Drop 提供了靜態網站免費寄存的服務, 只需要上傳 zip 檔, 馬上完成上線. ht [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Cloudflare Drop 提供了靜態網站免費寄存的服務, 只需要上傳 zip 檔, 馬上完成上線.</p>
<p><a href="https://www.cloudflare.com/drop/" target="_blank" rel="noopener">https://www.cloudflare.com/drop/</a></p>
<p>其實這個服務主要是依存於 workers and pages 的服務下, 也是屬於 serverless 的方式進行服務提供.</p>
<p>這裡不詳述如何使用, 可以參考以下文章:</p>
<ul>
<li><a href="https://www.minwt.com/free/24430.html" target="_blank" rel="noopener">https://www.minwt.com/free/24430.html</a></li>
<li><a href="https://free.com.tw/cloudflare-drop/" target="_blank" rel="noopener">https://free.com.tw/cloudflare-drop/</a></li>
</ul>
<p>上傳後, 你可以在 60分鐘內認領你的網站, 只需要註冊或登入即可, 若你有自己的域名, 也可以掛載在自己域名服務之下, 非常方便快速.</p>
<p>右上方界面有個提供給 AI使用的操作說明(copy for your agent), 可以提供給你的 AI進行了解並協助你作後續的開發應用:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">Fetch https://www.cloudflare.com/drop/llms.txt</pre>
<p>這裡做了一些小功能都是純前端的 Javascript 即可實現的工具箱:</p>
<p><a href="https://toolbox.diary.tw/" target="_blank" rel="noopener">https://toolbox.diary.tw/</a></p>
<p>提供了以下功能:</p>
<ul>
<li>Pi 計算器 &#8211; 提供了指定位數的 Pi 計算, 並可快速找到指定的字串, 如你的生日等.</li>
<li>線上抽獎轉盤 &#8211; 提供了抽獎轉盤, 方便抽獎活動使用.</li>
<li>QR Code 工具 &#8211; 提供了 QR Code 生成與解讀, 可以用上傳圖片或是照相的方式.</li>
<li>URL 編解碼 &#8211; 提供了 URL Encode 與 Decode 字串的功能.</li>
<li>密碼產生器 &#8211; 提供了指定位數與指定字串型態的密碼產生.</li>
<li>圖片壓縮轉檔 &#8211; 提供了上傳圖片可以快速轉換為對應格式與進行指定比例縮小功能, 剪裁, 旋轉, 上下與左右的鏡向, 並算出能節省多少大小.</li>
<li>PDF工具 &#8211; 提供了合併、拆分、旋轉工具, 都在本地執行, 安全無上傳檔案的風險. (2026/8/27 0:02). 新增可以將 PDF轉為圖片或由圖片轉為PDF的功能 (2026/9/12 12:39). 新增PDF壓縮工具, 解決常見想要壓縮但又擔心重要資料外流問題的功能. (2026/9/15 14:40).</li>
<li>證件浮水印與遮蔽 &#8211; 提供了在圖檔上馬賽克或模糊的多重遮蔽功能, 也提供了浮水印功能, 可以整個檔案或是局部上特定文字, 供申辦作業使用.</li>
</ul>
<p>以上工具都是不透過 server 就只在前端進行運算的功能, 方便大家使用!</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2760/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2760</post-id>	</item>
		<item>
		<title>到 local.ai 取得你的專屬網址</title>
		<link>https://diary.tw/archives/2749</link>
					<comments>https://diary.tw/archives/2749#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Fri, 14 Aug 2026 14:09:16 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[local]]></category>
		<category><![CDATA[model]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2749</guid>

					<description><![CDATA[這個網站 https://local.ai  提供了完整的本地運行 AI所需要的硬體資源, 模型選擇, 並將跑 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>這個網站 <a href="https://local.ai" target="_blank" rel="noopener">https://local.ai</a>  提供了完整的本地運行 AI所需要的硬體資源, 模型選擇, 並將跑分提供給大家做參考.</p>
<p>以往我們要找對應的資料可以在論壇上看看別人的經驗與硬體配置, 如什麼 CPU / DRAM / GPU / VRAM 等參數, 跑什麼模型什麼量化得到多少 tokens/sec 的數字, 當然後來有了 Can I Run AI &#8211; <a href="https://www.canirun.ai/" target="_blank" rel="noopener">https://www.canirun.ai/</a> 來查找.</p>
<p>現在可以透過這個 local.ai 服務來查找其他人硬體的跑分結果, 或是想執行什麼模型你可以先準備對應的硬體, 更容易找出適合的資源與預算, 也就是可以由這個服務取得真實的硬體執行結果的資訊!</p>
<p>不過無論你有沒有要跑本地 AI, 都可以先申請自己的專用網址, 請透過以下我的推薦碼連結進行申請:</p>
<p><a href="https://local.ai/timhuang/invite" target="_blank" rel="noopener">https://local.ai/timhuang/invite</a></p>
<p>一方面我也有機會可以獲得獎勵的硬體, 另一方面你也可以獲得一個專用的網址哦! (註冊需要用到你的 huggingface 帳戶)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2749/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2749</post-id>	</item>
		<item>
		<title>Squid Proxy的規則設定</title>
		<link>https://diary.tw/archives/2733</link>
					<comments>https://diary.tw/archives/2733#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Sat, 06 Jun 2026 01:52:52 +0000</pubDate>
				<category><![CDATA[好用軟體]]></category>
		<category><![CDATA[acl]]></category>
		<category><![CDATA[policy]]></category>
		<category><![CDATA[proxy]]></category>
		<category><![CDATA[squid]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2733</guid>

					<description><![CDATA[通常架設好 Squid Proxy 後, 用來做 Proxy 代理功能時, 會希望能限制可使用的來源 IP 或 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>通常架設好 Squid Proxy 後, 用來做 Proxy 代理功能時, 會希望能限制可使用的來源 IP 或是可訪問或不可訪問的 IP (除了做權限管控外, 還可以管理限制使用者可以訪問的目的網站).</p>
<p>今天有個需求是這樣的, 允許特定 IP 訪問特定的網站, 乍看下會這樣下:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="htaccess">acl AllowedIPs src 192.168.100.0/24
acl AllowedDomains dstdomain .google.com .yahoo.com
http_access allow AllowedIPs
http_access allow AllowedDomains
http_access deny all
</pre>
<p>但是這樣會變成 OR 的邏輯, 也就是只要白名單 IP, 或是白名單域名(包含子域名), 就會放行, 與原本需要的特定 IP 訪問特定網域不同.</p>
<p><span id="more-2733"></span></p>
<p>所以若是要 AND 的邏輯, 就必需寫在同一行如下:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="htaccess">acl AllowedIPs src 192.168.100.0/24 
acl AllowedDomains dstdomain .google.com .yahoo.com
http_access allow AllowedIPs AllowedDomains 
http_access deny all</pre>
<p>這樣就只有特定 IP 訪問特定網域時才能使用, 否則都會是 403回應囉.</p>
<p>這在設定內網存取外網時特別有用.</p>
<p>官方文件: <a href="https://www.squid-cache.org/Doc/" target="_blank" rel="noopener">https://www.squid-cache.org/Doc/</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2733/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2733</post-id>	</item>
		<item>
		<title>如何檢測proxy工作是否正常</title>
		<link>https://diary.tw/archives/2728</link>
					<comments>https://diary.tw/archives/2728#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Sun, 31 May 2026 01:17:50 +0000</pubDate>
				<category><![CDATA[系統技術]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[proxy]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2728</guid>

					<description><![CDATA[若要檢測 proxy是否工作正常, 可以將 proxy設定在自己的瀏覽器中來進行, 並透過 IP查詢來看是否有 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>若要檢測 proxy是否工作正常, 可以將 proxy設定在自己的瀏覽器中來進行, 並透過 IP查詢來看是否有改變到 proxy server的IP就可以知道是否工作正常與正確設定完成.</p>
<p>不過若是想快速測試不想改動自己的 Browser設定, 可以用 curl 工具來進行測試, 說明如下:</p>
<p>正常不使用 Proxy的狀況來訪問:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">curl https://ip.diary.tw/</pre>
<p>可以問到自己的 IP. 若是要觀察 http header, 可以使用 -i, 會同時輸出 header 與察容, 或使用 -I來顯示 header only:</p>
<p><span id="more-2728"></span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">curl -i https://ip.diary.tw/
curl -I https://ip.diary.tw/</pre>
<p>若是多加上 proxy server, 則多加上 -x 或是 &#8211;proxy 方式指定 proxy server, 後面再加上要查詢的網址:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">curl -x http://[username]:[password]@proxy.example.com:80 https://ip.diary.tw/</pre>
<p>若 proxy server有要驗證, 可以同時將 [username]:[password]寫上來直接帶入, 若沒有則可以省略, 若只要查詢 header only就組合上面的指令:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">curl -x http://[username]:[password]@proxy.example.com:80 -I https://ip.diary.tw/</pre>
<p>這樣就可以準確而快速地測試 proxy server是否能正常工作並協助你帶不同的出口 IP.</p>
<p>參考資料:</p>
<ul>
<li><a href="https://oxylabs.io/blog/curl-with-proxy" target="_blank" rel="noopener">https://oxylabs.io/blog/curl-with-proxy</a></li>
<li><a href="https://stackoverflow.com/questions/9445489/performing-http-requests-with-curl-using-proxy" target="_blank" rel="noopener">https://stackoverflow.com/questions/9445489/performing-http-requests-with-curl-using-proxy</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2728/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2728</post-id>	</item>
		<item>
		<title>使用自定義 x-signature 在Cloudflare中來保護API</title>
		<link>https://diary.tw/archives/2721</link>
					<comments>https://diary.tw/archives/2721#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Fri, 29 May 2026 16:48:27 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[cloudflare]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2721</guid>

					<description><![CDATA[在 Cloudflare 中, 若是有一組自己的 API, 想要簡單地透過 Cloudflare 來保護, 有 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>在 Cloudflare 中, 若是有一組自己的 API, 想要簡單地透過 Cloudflare 來保護, 有很多方法, 不過大多需要是付費的版本才能提供, 像是 API Shield.</p>
<p>若是想要快速而輕量地達成這個 API的保護, 可以透過 Worker 來檢查 x-signature 的 header 來實現.</p>
<p>在 Cloudflare 的 Workers &amp; Pages 介面,  Create application, 然後給定一個名稱如 api-check, 然後在右上角的 Edit Code 進入程式編輯器.</p>
<p>輸入以下程式碼:</p>
<p><span id="more-2721"></span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">const EXPIRY_SECONDS = 300;

export default {
  async fetch(request, env, ctx) {
    // 1. 將您的秘密金鑰設定在環境變數 (安全起見建議後續設定為 Secret)
    const SECRET_KEY = env.API_SECRET_KEY;
    
    const url = new URL(request.url);
    const apiPath = url.pathname;
    const host = url.host;

    // 2. 擷取外部夥伴傳入的 X-Signature 標頭
    const xSignature = request.headers.get("X-Signature");
    if (!xSignature) {
      return new Response(JSON.stringify({ error: "Unauthorized: Missing X-Signature header" }), {
        status: 401,
        headers: { "Content-Type": "application/json" }
      });
    }

    // 3. 解析標頭格式 (預期格式: token-timestamp)
    const parts = xSignature.split("-");
    if (parts.length !== 2) {
      return new Response(JSON.stringify({ error: "Unauthorized: Invalid signature format" }), {
        status: 401,
        headers: { "Content-Type": "application/json" }
      });
    }
    const [clientToken, timestampStr] = parts;
    const clientTimestamp = parseInt(timestampStr, 10);

    // 4. 驗證時間戳記是否超時 (防止重放攻擊)
    const currentTimestamp = Math.floor(Date.now() / 1000);
    if (Math.abs(currentTimestamp - clientTimestamp) &gt; EXPIRY_SECONDS) {
      return new Response(JSON.stringify({ error: "Unauthorized: Signature expired" }), {
        status: 401,
        headers: { "Content-Type": "application/json" }
      });
    }

    // 5. 使用 Web Crypto API 在本端重新計算 HMAC-SHA256
    // 簽章組合公式：路徑 + 網域 + 時間戳記 (符合原 WAF v0 規範)
    const messageStr = `${apiPath}${host}${clientTimestamp}`;
    
    try {
      const encoder = new TextEncoder();
      const keyData = encoder.encode(SECRET_KEY);
      const messageData = encoder.encode(messageStr);

      const cryptoKey = await crypto.subtle.importKey(
        "raw",
        keyData,
        { name: "HMAC", hash: "SHA-256" },
        false,
        ["sign"]
      );

      const signatureBuffer = await crypto.subtle.sign("HMAC", cryptoKey, messageData);
      
      // 將計算結果轉為十六進位字串 (Hex)
      const serverToken = Array.from(new Uint8Array(signatureBuffer))
        .map(b =&gt; b.toString(16).padStart(2, '0'))
        .join('');

      // 6. 比對客戶端與伺服器端的 Token 是否一致
      if (clientToken !== serverToken) {
        return new Response(JSON.stringify({ error: "Unauthorized: Signature mismatch" }), {
          status: 401,
          headers: { "Content-Type": "application/json" }
        });
      }
    } catch (err) {
      return new Response(JSON.stringify({ error: "Internal Server Error during verification" }), {
        status: 500,
        headers: { "Content-Type": "application/json" }
      });
    }

    // 7. 驗證通過，將請求原封不動轉發 (Proxy) 給後端的真實源站
    // 註：fetch(request) 會保留原始的 URL、Header 與 Body
    return fetch(request);
  }
};</pre>
<p>其中的 <span class="enlighter-text">EXPIRY_SECONDS 就是限制這個 x-signature 效期只有 300 秒, 你可以依實際的狀況增加或減少這個過期秒數設定, 完成後按下 deploy.</span></p>
<p>然後我們要將這個程式中用到的 API_SECRET_KEY 放在 Workers &amp; Pages 的 Setting 中的 Variables, 所以按下左上角回到 Workers &amp; Pages 頁面, 切換到 Setting 頁籤, 在最上面的 Variables &amp; Secrets 中, add 一個 Secret 的變數, 內容請自訂, 如 x-123-456-789, 一樣要 deploy 即可, 到這裡完成 Workers 的程式準備.</p>
<p>接下來要透過 Domains 來綁定對應的 API 服務, 若你原本的 API 服務是在 myapi.example.com/api/v1/xxxx 這樣, 你可以在 Workers &amp; Pages 下的 Domains 中, Add Domain, 設定對應的主域名, 然後選擇 Route Pattern, 指定 myapi.example.com/api/* 這樣的路徑, 按下 add route 完成設定, 到這裡就把 server 端在 Cloudflare 上的配置設定完成了.</p>
<p>接下來就是 Client 的部分了, 由於有自定義了 x-signature header, 所以我們就是利用自己的程式來實作這個部分, 把 x-signature header 做出來, 再進行訪問即可, Python 程式如下:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">import hmac
import hashlib
import time
import requests
from urllib.parse import urlparse

# 1. 設定基本資料
SECRET_KEY = "x-123-456-789"

api_url = "https://myapi.example.com/api/v1/users"

parsed_url = urlparse(api_url)
api_path = parsed_url.path
host = parsed_url.hostname

# 2. 取得當前 Unix 時間戳記 (秒)
current_time = int(time.time())

# 3. 依照 Cloudflare 規範組合簽章訊息 (路徑 + 時間戳記)
# message = f"{api_path}{current_time}"
message = f"{api_path}{host}{current_time}"

# 4. 使用 HMAC-SHA256 進行雜湊，並轉為十六進位字串
token = hmac.new(
    SECRET_KEY.encode('utf-8'),
    message.encode('utf-8'),
    hashlib.sha256
).hexdigest()

# 5. 將「Token」與「時間戳記」用格式 `token-timestamp` 組合起來
# 這是 Cloudflare is_timed_hmac_valid_v1 函數要求的標準格式
x_signature = f"{token}-{current_time}"

# 6. 帶入 Header 發出請求
headers = {
    "X-Signature": x_signature
}

response = requests.get(api_url, headers=headers)
print(response.json())</pre>
<p>其中的 SECRET_KEY 與前面 Cloudflare 中設的 API_SECRET_KEY 設定為一樣的就可以了, 這樣就可以在不傳遞 shared key, 又可以有效地透過這個簡易的 x-signature header 來訪問 API了.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2721/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2721</post-id>	</item>
		<item>
		<title>網路升級了-1G/600M</title>
		<link>https://diary.tw/archives/2716</link>
					<comments>https://diary.tw/archives/2716#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Wed, 27 May 2026 02:39:14 +0000</pubDate>
				<category><![CDATA[懶得分類]]></category>
		<category><![CDATA[BROADBAND]]></category>
		<category><![CDATA[Kbro]]></category>
		<category><![CDATA[UPLINK]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2716</guid>

					<description><![CDATA[Kbro 提供了 1G/600M 方案, 大幅提升了上行的速度, 家裡網路由原來的 1G/50M 升上來, 加 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Kbro 提供了 1G/600M 方案, 大幅提升了上行的速度, 家裡網路由原來的 1G/50M 升上來, 加一點點價就可以將上行升級 12倍, 非常划算.</p>
<p>來測速看看吧:</p>
<p><img fetchpriority="high" decoding="async" class="aligncenter size-large wp-image-2717" src="https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-27-103454-1024x951.png" alt="" width="580" height="539" srcset="https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-27-103454-1024x951.png 1024w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-27-103454-300x279.png 300w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-27-103454-768x713.png 768w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-27-103454-1200x1114.png 1200w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-27-103454.png 1259w" sizes="(max-width: 580px) 100vw, 580px" /></p>
<p>很不錯的測速效果呢, 有架站的朋友可以試試吧!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2716/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2716</post-id>	</item>
		<item>
		<title>用Antigravity CLI繼續開發</title>
		<link>https://diary.tw/archives/2714</link>
					<comments>https://diary.tw/archives/2714#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Sun, 24 May 2026 16:09:39 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Antigravity CLI]]></category>
		<category><![CDATA[Gemini CLI]]></category>
		<category><![CDATA[Gemini Pro]]></category>
		<category><![CDATA[Google]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2714</guid>

					<description><![CDATA[繼之前的 Gemini CLI 開發 (請參考這篇 &#8211; https://diary.tw/arch [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>繼之前的 Gemini CLI 開發 (請參考這篇 &#8211; <a href="https://diary.tw/archives/2705" target="_blank" rel="noopener">https://diary.tw/archives/2705</a>), 由於最近的 Google I/O 大會, 宣佈了將下架 Gemini CLI, 轉到 Antigravity CLI, 所以我也得對應調整一下開發工具到 Antigravity CLI (簡稱 agy).</p>
<p>為了安裝 agy, 先看了一下官方資料, 原來必須先裝 Antigravity (IDE) 後才能安裝 Antigravity CLI (不過現在拿掉了 &#8211; <a href="https://antigravity.google/download#antigravity-cli" target="_blank" rel="noopener">https://antigravity.google/download#antigravity-cli</a>), 有兩件事我需要先確認才能將 Gemini CLI 轉到 Antigravity CLI:</p>
<ol>
<li>是否一定要 Antigravity (IDE)</li>
<li>是否仍可以使用連接 Gemini Pro 方案的帳戶而不只有 API連接方式</li>
</ol>
<p><span id="more-2714"></span></p>
<p>為了測試一下這兩個問題, 所以先開了一台 DigitalOcean VM 來安裝 Antigravity CLI:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="bash">curl -fsSL https://antigravity.google/cli/install.sh | bash</pre>
<p>很快地就裝好了, 然後用 agy 指令啟動, 一樣可以連接 Gemini Pro 帳戶, 連接程序與原本 Gemini CLI 相同, 於是就接著測一下開發的功能, 發現很快很不錯, 而且是用 Gemini Flash 3.5 模型, 比原本在 Gemini  CLI 中的最高 Gemini Pro 3.1 還要新, 而且介面比原本的好, 原來的 Gemini CLI 是用 node js 寫的, Antigravity CLI 則是改用 Go 寫的, 看起來有對介面再優化過了, 所以雖然不得不, 但也算是升級了.</p>
<p>於是就放心在原本的開發環境來安裝, 很快裝好後, 連接 Google 帳戶完成, 繼續來開發原本的專案, 效果很不錯, 而且也更快更強大了, 非常推薦原本在用 Gemini CLI 的朋友們快來升級到 Antigravity CLI.</p>
<p>另外原本在 Gemini CLI 在美國上班的尖峰時間會慢的問題, 在 Antigravity CLI 目前還沒有這個狀況, 再加上可用的模型更多, 非常值得升級.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2714/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2714</post-id>	</item>
		<item>
		<title>Gemini CLI開發經驗分享</title>
		<link>https://diary.tw/archives/2705</link>
					<comments>https://diary.tw/archives/2705#respond</comments>
		
		<dc:creator><![CDATA[tim]]></dc:creator>
		<pubDate>Mon, 04 May 2026 14:57:44 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Gemini]]></category>
		<category><![CDATA[Vibe Coding]]></category>
		<guid isPermaLink="false">https://diary.tw/?p=2705</guid>

					<description><![CDATA[如之前這篇 https://diary.tw/archives/2689提到, 目前已是開通 Gemini A [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>如之前這篇 <a href="https://diary.tw/archives/2689" target="_blank" rel="noopener">https://diary.tw/archives/2689</a>提到, 目前已是開通 Gemini AI Pro 方案的狀況下, 想說來試看看 Gemini CLI 寫寫程式, 看看效果如何, 結果用起來還挺方便好用的.</p>
<p>從無到有打造一個程式, 不用半天的時間, 第一個寫的小程式是python 專案, 利用 speedtest-cli 來進行網路的測速, 並且記錄到 sqlite 資料庫, 再利用 streamlit (這個是 Gemini CLI建議的) 來進行 dashboard 的介面展示, 整個專案很快就完成了, 的確非常快速方便, 畫面如下:</p>
<p><img decoding="async" class="aligncenter size-large wp-image-2706" src="https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-224553-1024x733.png" alt="" width="580" height="415" srcset="https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-224553-1024x733.png 1024w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-224553-300x215.png 300w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-224553-768x550.png 768w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-224553-1536x1099.png 1536w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-224553-1200x859.png 1200w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-224553.png 1649w" sizes="(max-width: 580px) 100vw, 580px" /></p>
<p><span id="more-2705"></span></p>
<p>於是就打算再來寫個更複雜一點的程式, 就是一個小型的社群網站, 這次就和 AI 互動比較多, 先討論規畫再實作, 於是用 Nodejs 與 Mysql (後來還加上了 Redis 可以加速快取) 來進行這個社群網站的開發, 做得來有模有樣的, 真的很不錯, 花了一共約 10多個小時 (分好幾天進行), 有個雛形出來了, 目前已有的功能有會員、好友、通知、發文(含相片、編輯、刪除)、留言、按讚、hashtag、後台管理等, 貼文中支援 markdown 語法、Youtube 連結會自動 embed youtube player 、Instagram 相片、reel 連結自動 embed 對應語法等功能, 會再持續增加更多的功能進行, 目前就想成一個都是公開內容的 facebook 吧!</p>
<p>一開始用還蠻順利的, 而且 quota 還蠻大的, 但是最近發現晚上 Gemini 反應速度大幅下降了, 白天還好, 所以可以多利用白天來進行或是就把指令給出讓它自行執行(RUN 在 tmux session 裡才不會登出), 這樣就可以用零散的時間來進行開發了.</p>
<p>有興趣的網友們可以玩看看, 也順便給些建議吧!</p>
<p>網址: <a href="https://socialnet.diary.tw/" target="_blank" rel="noopener">https://socialnet.diary.tw/</a></p>
<p><img loading="lazy" decoding="async" class="aligncenter size-large wp-image-2707" src="https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-225456-933x1024.png" alt="" width="580" height="637" srcset="https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-225456-933x1024.png 933w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-225456-273x300.png 273w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-225456-768x843.png 768w, https://diary.tw/files/2026/05/螢幕擷取畫面-2026-05-04-225456.png 1190w" sizes="auto, (max-width: 580px) 100vw, 580px" /></p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://diary.tw/archives/2705/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2705</post-id>	</item>
	</channel>
</rss>
