2025年2月18日 星期二

如何在 Colab 平台設定時區

Colab 是一個非常方便的 Python 執行平台, 除了內建的標準函式庫外, 也已經預先安裝了許多常用的第三方套件 (主要是資料科學與機器學習套件), 幾乎毋須配置環境即可馬上執行 Python 應用程式. 如果套件或模組無法直接 import 進來, 表示 Colab 沒有預先安裝, 可用 !pip install 指令自行安裝. 

本系列之前的文章參考 :

如何在 Colab 中隱藏與取用密鑰

本篇要來測試如何將 Colab 上預設的 UTC 日期時間改為本地時間.


1. 利用 os 與 time 模組設定時區 : 

Colab 的虛擬機器時區預設是 UTC 時區, 例如下列指令執行後印出的是 UTC 時間 :

from datetime import datetime   
print(datetime.now())   




現在台灣時間為下午近五點, 但顯示的卻是早上近九點, 差了 8 小時 (台灣是 UTC+8). 

可以匯入 os 與 time 模組後利用 os.environ['TZ'] 設定時區為 'ASIA/Taipei', 然後呼叫 time.tzset() 函式設定時區, 這樣 datetime.now() 就會印出台灣時間了 : 

import os   
import time   

os.environ['TZ']='Asia/Taipei'  
time.tzset()   





2. 利用第三方套件 pytz 設定時區 :   

先匯入 pytz 模組 (目前 Colab 已經預先安裝了) :

import pytz   

然後呼叫其 timezone() 函式並傳入 'ASIA/Taipei' 將時區設定為台灣時區後, 呼叫 datetime 物件的 astimezone() 方法並傳入 TimeZone 物件即可 : 

tz=pytz.timezone('Asia/Taipei')  
utc_now=datetime.now(pytz.utc)  
print(utc_now)    
print(utc_now.astimezone(tz))    



2025年2月17日 星期一

好站 : 範例檔案資料庫網站 samplelib.com

今天為了測試 Gradio 的 Video 元件搜尋線上 mp4 檔案, 找到下面這個好用的範例文件資料庫網站 samplelib.com :





此網站提供視訊 (MP4, WEBM), 音訊 (MP3, WAV), 圖片 (JPEG, PNG, SVG, GIF), Excel 檔, 廣告橫幅, 以及排版用的 Lorem ipsum 文字檔等範例, 可供直接以 URL 方式線上或下載免費無限制使用. 

以視訊檔為例, 點擊首頁上方 Video 選單中的 mp4 選項會列出所有視訊檔範例列表, 點擊右方按鈕即可下載檔案 :




如果要線上使用, 在視訊檔上按滑鼠右鍵, 點選 "複製影片位址" 即可取得 URL :




例如第一個影片網址為 : 

https://samplelib.com/lib/preview/mp4/sample-5s.mp4

將此 URL 傳給 Gradio 的 Video 元件就可以在 web app 中播放此影片了. 

2025年2月16日 星期日

2025 年第 7 周記事

本周重要事項為周四 (2/13) 辦理阿蘭安金滿月祭祀, 我上週即已籌備妥當, 周四請早上半天假, 週三下班後經自由路買了一對花束回鄉下, 先至退伍軍人取預定之發粄與紅龜粄, 週四早上仍下小雨, 八點時剛好暫歇, 便與爸出發前往墓園祭拜. 到斟第三回酒時又下起雨來, 趕緊燒金放鞭炮, 然後點香收祭品, 酒杯裡的米酒都摻了一些雨水了. 至此阿蘭的身後事總算圓滿了. 

這一周三天兩頭都在下雨, 天氣又冷又濕, 晾乾的衣服總覺得不夠乾爽還得用乾衣機烘個幾分鐘. 週六總算迎來太陽 (中午還超級熱), 早上載菁菁回楠梓工作室後回鄉下. 周末主要工作是烹飪, 把冰箱祭祀用的雞肉做麻油雞, 豬肉做成紅燒肉, 帶回高雄當下周午餐便當的主菜. 還有過年拜拜用的麵條, 因為剛好全聯買一送一, 結果現在廚房堆了四大包關廟麵, 今日中午就煮台式炒麵來消耗一些. 

晒穀場邊的波蘿蜜已結實累累, 今日中午得空便拿了梯子進行疏果, 每個分支僅留一顆較大的果實, 其餘全部切除, 避免營養分散每顆都長不大. 往年我都無暇疏果任其生長, 節實太密導致有些小果被夾在中間很容易爛掉. 去年都沒有送農會拍賣, 爸的波羅蜜外快收入有限, 今年要好好來看顧, 我可以周一載去農會交運後再去高雄上班, 因為現在彈性上班往後延到 09:30 時間綽綽有餘. 



二哥碩二 (下) 註冊

今天幫二哥線上註冊碩二下的學雜費, 共 32716 元 : 




大部分是宿舍費啦. 二哥說他論文包含兩顆晶片, 目前已完成一顆, 還有一顆晶片新學期要下, 加上論文撰寫可能要碩三上才畢業. 他室友資工所的台北人, 下學期只要準備論文沒有課了, 所以新學期退宿了, 二哥還要住宿舍一年哩. 但校內住宿補貼不知道下個學年度還有沒有, 真的要感謝藍白幫納稅人看緊荷包, 真的啦. 

2025年2月15日 星期六

momo 購買茶几與收納櫃

除夕大掃除時發現老家客廳的茶几被蛀蟲侵蝕, 四支腳已經有一支被蛀空, 只要稍用力壓就可能垮掉, 去鎮上家具行看了一下, 一個要價 3000 元實在太貴了, 只好等過完年再來尋覓. 今天早上去燦坤看洗衣機回來, 想到茶几也要換, 便上 momo 找到下面這款 : 





另外餐廳的四格木櫃也被白蟻啃蝕, 最近要將其全部清除, 換成塑膠收納櫃, 靠樓梯那邊的受樓梯限制擺這個三層櫃 : 






靠電視這側的買四層櫃, 買兩組, 另一組放鞋櫃上面 : 





總計需付 2969 元, 用掉 momo 幣 189 元, 實付 2771 元 :





有登記送 10% momo 幣活動, 但今天已滿額, 明晚 9 點再登記 : 



2025年2月14日 星期五

Python 學習筆記 : 使用 DuckDuckGo API 搜尋網路資料 (二)

在前一篇測試中, 我們對 DuckDuckGo API 用法已有基本了解, 只要安裝第三方套件 duckduckgo-search 即可在應用程式中透過 DuckDuckGo API 搜尋文字, 圖片, 影片, 新聞等內容, 甚至可與 GPT 語言模型聊天, 參考本系列前一篇文章 :


本篇則要使用 Gradio 作為網頁應用程式介面來顯示從 DuckDuckGo 搜尋到的圖片. 


8. 使用 Gradio 製作圖片搜尋介面 : 

Gradio 是 Hugging Face 旗下的一款輕量級開放原始碼 Python web app 套件, 開發者毋須具備任何網頁前端技術 (例如 HTML, CSS, Javascript), 只需少許 Python 程式碼即可快速建構一個網頁應用程式介面, 用法參考 :


Gradio 官網提供 Playground 讓開發者線上撰寫 Web app, 網址如下 : 


在 Gradio Playgorund 上編寫的應用程式可以一鍵部署到 Hugging Face 的免費 Web app 空間 Hugging Face Space (也可付費取得更多資源), 參考 : 


Hugging Face Space 已安裝一些常用的 Python 第三方套件, 例如 Numpy, Pandas, Matplotlib 等等, 通常在 Gradio Playgorund 上可以順利執行的 Web app 發布到 Hugging Face Space 後應該均可順利運行, 如果出現找不到套件或模組的錯誤, 就要到 Hugging Face Space 上手動新增一個專案, 並在 requirement.txt 檔案中指定要安裝之第三方套件, 參考 :


不過壞消息是, 由於透過 DuckDuckGo API 搜尋資料需要 requests 或 urllib 等爬蟲套件, 但 Gradio Playground 與 Hugging Face Space 可能基於資安原因均無法執行這些爬蟲套件, 因此以下測試均在本機執行. 

Gradio 用來展示圖片的元件為 Gallery, 用法參考 : 


全部 Gradio 測試紀錄參考索引 :


測試程式碼如下 :

# gradio-duckduckgo-images-gallery-1.py
import gradio as gr
from duckduckgo_search import DDGS

def handler(query, max_results):
    results=ddgs.images(query, max_results=int(max_results))  # 需用 int() 轉成整數
    return [result['thumbnail'] for result in results]
    
ddgs=DDGS()
in1=gr.Textbox(label='輸入關鍵字', value='可愛的貓')
in2=gr.Textbox(label='設定圖片數量', value=8)
out1=gr.Gallery(label='DuckDuckGo 圖片搜尋結果', columns=4, object_fit='scale-down')
iface=gr.Interface(
    fn=handler,
    inputs=[in1, in2],
    outputs=out1,
    title='DuckDuckGo 圖片搜尋測試',
    flagging_mode='never',
    )
iface.launch()

此例設置了兩個 TextBox 輸入元件, in1 負責接收搜尋關鍵字, in2 負責接收欲取得之圖片數量 (即取前幾個搜尋結果), 這兩個參數會依序傳入處理函式 fn=handler, 分別對應到 query 與 max_results, 然後傳給 DDGS 物件的 images() 方法進行圖片搜尋, 然後從 DuckDuckGo API 回應的字典串列中, 取出 thumbnail 鍵所攜帶的縮圖 URL 組成串列傳回給 Gallery 元件顯示. 注意, 由於 Textbox 元件輸出字串, 但 max_results 參數要求為一個整數, 故需先用 int() 轉換. 

結果如下 : 




因為 Gallery 元件指定 columns=4, 所以圖片會以 4 欄呈現, 點擊這些小圖就會彈出一個較大視窗來顯示這些縮圖 (不是原始圖檔). 如果將 handler() 中的傳回值改成擷取原本圖檔的 URL 鍵 image 亦可 : 

return [result['image'] for result in results]

但因為 Gradio 的 Gallery 能顯示的圖檔尺寸有限, 太大的圖檔會無法呈現, 例如 : 




也可以用 Number 或 Slider 元件來設定圖片數量, 它們都是傳回數值, 因此毋須使用 int() 來轉換 in2 元件的傳出值, 例如 : 

# gradio-duckduckgo-images-gallery-2.py
import gradio as gr
from duckduckgo_search import DDGS

def handler(query, max_results):
    results=ddgs.images(query, max_results=max_results)
    return [result['thumbnail'] for result in results]
    
ddgs=DDGS()
in1=gr.Textbox(label='輸入關鍵字', value='可愛的貓')
in2=gr.Number(label='設定圖片數量', minimum=1, value=8, maximum=100)
out1=gr.Gallery(label='DuckDuckGo 圖片搜尋結果', columns=4, object_fit='scale-down')
iface=gr.Interface(
    fn=handler,
    inputs=[in1, in2],
    outputs=out1,
    title='DuckDuckGo 圖片搜尋測試',
    flagging_mode='never',
    )
iface.launch()

結果如下 : 





下面是使用 Slider 的範例 :

# gradio-duckduckgo-images-gallery-3.py
import gradio as gr
from duckduckgo_search import DDGS

def handler(query, max_results):
    results=ddgs.images(query, max_results=max_results)
    return [result['thumbnail'] for result in results]
    
ddgs=DDGS()
in1=gr.Textbox(label='輸入關鍵字', value='可愛的貓')
in2=gr.Slider(label='設定圖片數量', minimum=1, value=8, maximum=100, step=1)
out1=gr.Gallery(label='DuckDuckGo 圖片搜尋結果', columns=4, object_fit='scale-down')
iface=gr.Interface(
    fn=handler,
    inputs=[in1, in2],
    outputs=out1,
    title='DuckDuckGo 圖片搜尋測試',
    flagging_mode='never',
    )
iface.launch()

由於 Slider 滑動步階預設為 0.1, 因此這裡要將 step 設為 1 (上面的 Number 元件沒有 step 參數, 因為它固定為 1, 結果如下 : 



2025年2月12日 星期三

Python 學習筆記 : 使用 DuckDuckGo API 搜尋網路資料 (一)

最近在讀旗標的 "LangChain 開發手冊" 這本書時看到 DuckDuckGo 搜尋引擎的訊息 (LangChain 工具集有內建 DuckDuckGoSearchAPIWrapper 類別), 以前在安裝不知哪款瀏覽器時似乎預設搜尋引擎是 DuckDuckGo, 但是在 Google 主宰搜尋市場時代, 誰還會去用甚麼鴨子搜尋引擎呢? 但今天深入了解後才發現它的好, 優點摘要如下 :
  • 使用方便 : 提供免費且不需要金鑰的 API, 可整合到應用程式中
  • 保護隱私 : DuckDuckGo 瀏覽器不追蹤使用者, 不收集個人資料, 不紀錄瀏覽歷史 
  • 立場中立 : 不過濾搜尋結果 (谷歌根據使用者資料提供個人化搜尋結果) 
  • 廣告簡單 : 僅依據搜尋關鍵字提供直接相關之簡單廣告 (谷歌提供個人化廣告)
  • 輕量快速 : 網站無過多的廣告與追蹤腳本程式碼, 執行效能高
於是立馬來測試一下 DuckDuckGo API 的用法, 其 API 網址如下 :


可以直接用瀏覽器連線此網站手動輸入關鍵字進行搜尋 : 




也可以透過第三方套件於自己的應用程式中呼叫其 API 取得搜尋結果. 


1. 安裝 duckduckgo-search 套件 : 

如果要在應用程式中使用 DuckDuckGo API 取得搜尋結果, 要先用 pip install 安裝 duckduckgo-search 套件 :

pip install duckduckgo-search   

D:\python\test>pip install duckduckgo-search   
Collecting duckduckgo-search
  Downloading duckduckgo_search-7.3.2-py3-none-any.whl.metadata (17 kB)
Collecting click>=8.1.8 (from duckduckgo-search)
  Downloading click-8.1.8-py3-none-any.whl.metadata (2.3 kB)
Collecting primp>=0.11.0 (from duckduckgo-search)
  Downloading primp-0.12.0-cp38-abi3-win_amd64.whl.metadata (13 kB)
Collecting lxml>=5.3.0 (from duckduckgo-search)
  Downloading lxml-5.3.1-cp310-cp310-win_amd64.whl.metadata (3.8 kB)
Requirement already satisfied: colorama in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from click>=8.1.8->duckduckgo-search) (0.4.6)
Downloading duckduckgo_search-7.3.2-py3-none-any.whl (19 kB)
Downloading click-8.1.8-py3-none-any.whl (98 kB)
Downloading lxml-5.3.1-cp310-cp310-win_amd64.whl (3.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.8/3.8 MB 4.1 MB/s eta 0:00:00
Downloading primp-0.12.0-cp38-abi3-win_amd64.whl (3.1 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.1/3.1 MB 7.0 MB/s eta 0:00:00
Installing collected packages: primp, lxml, click, duckduckgo-search
  Attempting uninstall: lxml
    Found existing installation: lxml 4.9.3
    Uninstalling lxml-4.9.3:
      Successfully uninstalled lxml-4.9.3
  Attempting uninstall: click
    Found existing installation: click 8.1.7
    Uninstalling click-8.1.7:
      Successfully uninstalled click-8.1.7
Successfully installed click-8.1.8 duckduckgo-search-7.3.2 lxml-5.3.1 primp-0.12.0

安裝後的套件名稱是 duckduckgo_search, 先匯入整個套件 :

>>> import duckduckgo_search    
>>> duckduckgo_search.__version__   
'7.3.2'

用 dir() 檢視套件內容 :

>>> dir(duckduckgo_search)   
['DDGS', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 'duckduckgo_search', 'exceptions', 'logging', 'utils', 'version'] 

這些成員中的核心是 DDGS 類別, 其他都是子模組, 除 exceptions 開發者可用來處理例外, 其餘均為內部使用. 


2. 建立 DDGS 物件 : 

使用 DuckDuckGo API 搜尋必須先建立 DDGS 物件, 首先匯入 DDGS 類別, 然後呼叫其建構式 DDGS() 來建立物件 : 

>>> from duckduckgo_search import DDGS   
>>> ddgs=DDGS()     
>>> type(ddgs)   
<class 'duckduckgo_search.duckduckgo_search.DDGS'>  

用 dir() 檢視 DDGS 物件內容 : 

>>> dir(ddgs)   
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_chat_messages', '_chat_models', '_chat_tokens_count', '_chat_vqd', '_get_url', '_get_vqd', '_impersonates', '_impersonates_os', '_sleep', '_text_html', '_text_lite', 'chat', 'client', 'headers', 'images', 'news', 'parser', 'proxy', 'sleep_timestamp', 'text', 'videos']

其中 client, headers, proxy, parser, sllep_timestamp 五個為屬性, 大部分為 DDGS 內部使用或很少用到, 其餘為物件方法, 也是 DDGS 主要的功能所在, 提供文字, 圖片, 視訊, 新聞等搜尋功能, 以及聊天機器人, 用法說明摘要如下表 : 


DDGS 物件方法 說明
chat(query, model='gpt-3.5-turbo') AI 聊天機器人 (可指定 gpt-4o-mini 模型).
text(query, max_results=10, region='us', safesearch='moderate', timelimit=None) 一般文字搜尋, 回傳標題, 網址與摘要.
images(query, max_results=10, safesearch='moderate') 圖片搜尋, 回傳圖片 URL 及縮圖.
videos(query, max_results=10, region='us', safesearch='moderate') 影片搜尋, 回傳影片標題與連結.
news(query, max_results=10, region='us', safesearch='moderate') 新聞搜尋, 回傳新聞標題, 網址與摘要.


3. 文字搜尋 :  

呼叫 DDGS 物件的 text() 方法並傳入關鍵字 (也可指定搜尋區域 region 與傳回筆數 max_results 等參數) 進行搜尋會傳回一個包含標題, 網址, 摘要等搜尋結果的字典串列, 例如 : 

>>> query='Langchain'  
>>> results=ddgs.text(query)   
>>> type(results)   
<class 'list'> 
>>> len(results)   
10

可見傳回值是一個串列, 如果沒有指定 max_results 參數預設是最多傳回 10 筆搜尋結果. 檢視串列元素為字典, 包含 title (網頁標題), href (網址), 與 body (內容) 三個鍵 : 

>>> type(results[0])  
<class 'dict'>  
>>> results[0]   
{'title': 'LangChain', 'href': 'https://www.langchain.com/', 'body': '"Working with LangChain and LangSmith on the Elastic AI Assistant had a significant positive impact on the overall pace and quality of the development and shipping experience. We couldn\'t have achieved the product experience delivered to our customers without LangChain, and we couldn\'t have done it at the same pace without LangSmith."'}
>>> results[0].keys()   
dict_keys(['title', 'href', 'body'])

傳入 max_results 參數可以指定最多傳回幾筆搜尋結果, 例如 :

>>> results=ddgs.text(query, max_results=5)   
>>> len(results)      
5

下面利用迴圈輸出這 5 筆搜尋結果的標題 (title) 與超連結 (href) :

>>> i=1   
>>> for result in results:   
    print(f'{i}. {result["title"]}\n{result["href"]}')   
    i += 1   
    
1. LangChain
https://www.langchain.com/
2. Introduction | ️ LangChain
https://python.langchain.com/docs/introduction/
3. GitHub - langchain-ai/langchain: Build context-aware reasoning ...
https://github.com/langchain-ai/langchain
4. LangChain - Wikipedia
https://en.wikipedia.org/wiki/LangChain
5. LangChain
https://www.langchain.com/langchain

也可以傳入 region 參數限制搜尋結果網頁的地區與語言, 例如台灣繁體中文的 region 代號為 'zh-tw' : 

>>> results=ddgs.text(query, region='zh-tw', max_results=5)   
>>> i=1    
>>> for result in results:   
    print(f'{i}. {result["title"]}\n{result["href"]}')   
    i += 1   

1. LangChain
https://www.langchain.com/
2. LangChain是什麼?AI開發者必須了解的LLM開源框架 - ALPHA Camp
https://tw.alphacamp.co/blog/langchain-intro
3. LangChain 框架介绍 | ️ Langchain
https://docs.langchain.com.cn/docs/introduction/
4. 快速入門 | ️ LangChain 框架
https://langchain-python.dev.org.tw/docs/get_started/quickstart/
5. 一文搞懂LangChain是什么(非常详细),零基础入门到精通,看这一篇就够了-CSDN博客
https://blog.csdn.net/weixin_49895216/article/details/142848013

不過看起來似乎不分簡體繁體, 只要是中文都包含在內. 


4. 圖片搜尋 :  

呼叫 DDGS 物件的 images() 方法並傳入關鍵字 (也可指定搜尋區域 region 與傳回筆數 max_results 等參數) 會傳回一個包含網頁標題與網址, 圖片與其縮圖網址, 圖片尺寸等搜尋結果的字典串列, 例如 : 

>>> query='可愛的貓'  
>>> results=ddgs.images(query, max_results=5)  
>>> type(results)  
<class 'list'>  

檢視第一個元素內容為紀錄網頁網址, 圖片網址, 與圖片尺寸等訊息的字典 : 

>>> results[0]   
{'title': '真想養貓!6種適合新手認養的可愛貓咪 | 布偶貓 | 網紅貓 | 大紀元', 'image': 'https://i.epochtimes.com/assets/uploads/2020/10/shutterstock_1665879682.jpg', 'thumbnail': 'https://tse2.mm.bing.net/th?id=OIP.siVhfvYFrZi77bBl4fAJBgHaE7&pid=Api', 'url': 'https://www.epochtimes.com/b5/20/10/13/n12472751.htm', 'height': 3016, 'width': 4525, 'source': 'Bing'}
>>> results[0].keys()  
dict_keys(['title', 'image', 'thumbnail', 'url', 'height', 'width', 'source'])

其中 title 為網頁標題, images 為圖片網址, url 為包含此圖片之網頁的網址, height 與 width 分別為圖片之高度與寬度 (px), source 為網頁來源, thumbnail 為縮圖網址. 按圖片網址即可看到此圖片 : 





用迴圈列出這五筆圖片 : 

>>> i=1    
>>> for result in results:
    print(f'{i}. {result["title"]}:\n{result["image"]}')
    i += 1   
    
1. 真想養貓!6種適合新手認養的可愛貓咪 | 布偶貓 | 網紅貓 | 大紀元:
https://i.epochtimes.com/assets/uploads/2020/10/shutterstock_1665879682.jpg
2. 【貓桌布】可愛喵合集!13款治癒系喵星人桌布,快讓你的桌面被喵星人佔領~ | CatCity 貓奴日常:
https://image.presslogic.com/cats.presslogic.com/wp-content/uploads/2021/03/c3671215.jpeg
3. 【手機壁紙】第二五期 可愛貓咪壁紙 - 每日頭條:
https://i2.kknews.cc/SIG=bbhro/61690001p648srn7rnqp.jpg
4. 可爱猫|快乐版 - 全部作品 - 素材集市:
http://img.sucaijishi.com/uploadfile/2023/0210/20230210100626916.png?imageMogr2/format/jpg/blur/1x0/quality/60
5. 可爱的猫 向量, 可愛的, 画, 卡通貓向量圖案素材免費下載,PNG,EPS和AI素材下載 - Pngtree:
https://png.pngtree.com/png-clipart/20230430/original/pngtree-cute-cat-png-image_9126653.png


5. 新聞搜尋 :  

呼叫 DDGS 物件的 news() 方法並傳入關鍵字 (也可指定搜尋區域 region 與傳回筆數 max_results 等參數) 會傳回一個包含標題, 網址, 摘要等搜尋結果的字典串列, 例如 : 

>>> query='Taiwan'  
>>> results=ddgs.news(query, max_results=5)  
>>> type(results)  
<class 'list'>  

檢視第一個元素內容, 可見此字典包含新聞日期, 標題, 內容, 網頁網址, 圖片網址, 以及新聞來源等 : 

>>> results[0]   
{'date': '2025-02-12T01:22:00+00:00', 'title': 'Taiwan environment minister eyes insurance funds to help with green transition', 'body': "Taiwan aims to get more than $1.5 billion in investment from insurance funds to help finance the island's green energy transition as part of its climate change and carbon reduction goals, Environment Minister Peng Chi-ming has said.", 'url': 'https://www.reuters.com/sustainability/sustainable-finance-reporting/taiwan-environment-minister-eyes-insurance-funds-help-with-green-transition-2025-02-12/', 'image': 'https://www.reuters.com/resizer/v2/HAZKYEC4ONNSFIRMNE3YL3X5FE.jpg?auth=63a2bee4ac149ad73c2938a9370ebc61fbe9142fc0b572a4d3fac552c7f9ad93&height=1005&width=1920&quality=80&smart=true', 'source': 'Reuters'} 
>>> results[0].keys()   
dict_keys(['date', 'title', 'body', 'url', 'image', 'source'])   

用迴圈列出這五筆新聞 : 

>>> i=1   
>>> for result in results:   
    print(f'{i}. {result["title"]}:\n{result["title"]}\n{result["body"]}\n')   
    i += 1    
    
1. Taiwan environment minister eyes insurance funds to help with green transition:
Taiwan environment minister eyes insurance funds to help with green transition
Taiwan aims to get more than $1.5 billion in investment from insurance funds to help finance the island's green energy transition as part of its climate change and carbon reduction goals, Environment Minister Peng Chi-ming has said.

2. Taiwan looks to buy Alaskan natural gas as it seeks to head off US tariffs:
Taiwan looks to buy Alaskan natural gas as it seeks to head off US tariffs
TAIPEI (Reuters) -Taiwan is interested in natural gas from Alaska and will continue to assess the feasibility of purchases, the economy ministry said on Monday, as the government looks to narrow the trade surplus with the United States and head off tariffs.

3. Taiwan detects 62 Chinese aircraft as US ships transit waters:
Taiwan detects 62 Chinese aircraft as US ships transit waters
Taiwan said Wednesday it detected 62 Chinese military aircraft near the self-ruled island this week, as two US ships sailed through the sensitive Taiwan Strait.

4. Chinese Military Monitored US Ship Crossing Taiwan Strait, State Media Reports:
Chinese Military Monitored US Ship Crossing Taiwan Strait, State Media Reports
(Reuters) - China's military said it organised naval and air forces to monitor the navigation operations of a U.S. destroyer and oceanographic survey ship crossing the Taiwan Strait from February 10-12, according to state broadcaster CCTV on Tuesday.

5. Hope film 'Ne Zha 2' to be screened in Taiwan island as soon as possible: spokesperson:
Hope film 'Ne Zha 2' to be screened in Taiwan island as soon as possible: spokesperson
In response to heated discussions about "Ne Zha 2" on the island of Taiwan, Zhu Fenglian, spokesperson for the State Council Taiwan Affairs Office, expressed the wish on Wednesday's press conference that the film will be screened in the island as soon as possible,


6. 影片搜尋 :  

呼叫 DDGS 物件的 videos() 方法並傳入關鍵字 (也可指定搜尋區域 region 與傳回筆數 max_results 等參數) 會傳回一個影片搜尋結果的字典串列, 例如 : 

>>> query='APT'    
>>> results=ddgs.videos(query, max_results=5)    
>>> type(results)  
<class 'list'>  
>>> len(results)     
5

檢視第一個元素內容 : 

>>> results[0]   
{'content': 'https://www.youtube.com/watch?v=ekr2nIex040', 'description': "ROSÉ & Bruno Mars - APT. Download/stream: https://rosesarerosie.lnk.to/APTID Order APT. single CD: https://rosesarerosie.lnk.to/APT-CDID 'rosie' - the first studio album by ROSÉ - out now download/stream: http://rosesarerosie.lnk.to/rosieID ROSÉ store exclusive 'rosie' vinyl, cd's, and more available now: http://rosesarerosie.lnk.to/storeID ...", 'duration': '2:54', 'embed_html': '<iframe width="1280" height="720" src="https://www.youtube.com/embed/ekr2nIex040?autoplay=1" frameborder="0" allowfullscreen></iframe>', 'embed_url': 'https://www.youtube.com/embed/ekr2nIex040?autoplay=1', 'image_token': '0be8410e804bf8c9e7c153c4f1747a34f92023b265a805e271710c9b129f9e62', 'images': {'large': 'https://tse1.mm.bing.net/th?id=OVP.u9EjUh1N1E2_3aDLeeiQNAHgFo&pid=Api', 'medium': 'https://tse1.mm.bing.net/th?id=OVP.u9EjUh1N1E2_3aDLeeiQNAHgFo&pid=Api', 'motion': 'https://tse2.mm.bing.net/th?id=OM.cEYhVc1Do-7hdA_1731902268&pid=Api', 'small': 'https://tse1.mm.bing.net/th?id=OVP.u9EjUh1N1E2_3aDLeeiQNAHgFo&pid=Api'}, 'provider': 'Bing', 'published': '2024-10-18T04:00:07.0000000', 'publisher': 'YouTube', 'statistics': {'viewCount': 1082191568}, 'title': 'ROSÉ & Bruno Mars - APT. (Official Music Video)', 'uploader': 'ROSÉ'}

檢視字典的鍵 : 

>>> results[0].keys()    
dict_keys(['content', 'description', 'duration', 'embed_html', 'embed_url', 'image_token', 'images', 'provider', 'published', 'publisher', 'statistics', 'title', 'uploader'])

其中 content 為影片網址, title 是影片標題, embed_html 是影片嵌入網頁碼, embed_url 是影片嵌入網址, duration 是影片長度, images 是影片不同解析度的縮圖 (有 small, medium, 與 large 等尺寸) 網址, published 是發佈時間等等. 





用迴圈列出這五筆影片搜尋結果 :

>>> i=1   
>>> for result in results:  
    print(f'{i}. {result["title"]}:\n{result["content"]}')   
    i += 1   
    
1. ROSÉ & Bruno Mars - APT. (Official Music Video):
https://www.youtube.com/watch?v=ekr2nIex040
2. ROSÉ & Bruno Mars - APT. (live from 2024 MAMA AWARDS):
https://www.youtube.com/watch?v=Jn8KvdWagfo
3. ROSÉ - APT. in the Radio 1 Live Lounge:
https://www.youtube.com/watch?v=Lwv254J8Ozk
4. APT Bruno Mars and Rosé | Learn the Viral Dance | Step-by-Step Beginner Tutorial:
https://www.youtube.com/watch?v=XxOAEpW8rPs
5. APT Bruno Mars and Rosé | Learn the Viral Dance | Practice it with Music:
https://www.youtube.com/watch?v=Cysgn9xOt-Q


7. 聊天機器人 :  

呼叫 DDGS 物件的 chat() 方法並傳入提示詞會傳回一個回應字串, 例如 : 

>>> prompt='Who are you?'   
>>> reply=ddgs.chat(prompt)   
>>> type(reply)   
<class 'str'>   
>>> reply  
'I am an AI language model created by OpenAI, designed to assist with a wide range of questions and tasks by providing information and generating text based on the input I receive. How can I help you today?'

問它使用甚麼模型只回答 GPT-3 :

>>> prompt='Please tell me your specific model name'    
>>> ddgs.chat(prompt)   
"I am based on OpenAI's GPT-3 model. If you have any specific questions or need assistance, feel free to ask!"

追問它版本代號是否為 gpt-3.5-turbo, 回答 Yes :

>>> prompt='Are you using gpt-3.5-turbo?'   
>>> ddgs.chat(prompt)   
'Yes, I am based on the GPT-3.5-turbo model. If you have any questions or need assistance, feel free to ask!'

用中文也可以 : 

>>> prompt='高雄有哪些代表性美食(請用繁體中文 zh-hant 回答)?'   
>>> ddgs.chat(prompt)   
'高雄是台灣的美食天堂,擁有許多代表性的美食。以下是一些高雄的特色美食:\n\n1. **六合夜市小吃**:六合夜市是高雄最著名的夜市之一,這裡有各式各樣的小吃,如鹽酥雞、蚵仔煎、魷魚羹等。\n\n2. **海鮮**:高雄靠近海邊,新鮮的海鮮是當地的特色。可以品嚐到生魚片、蒸螃蟹、烤魚等美味。\n\n3. **牛肉麵**:高雄的牛肉麵也相當有名,湯頭濃郁,牛肉軟嫩,搭配手工麵條,讓人回味無窮。\n\n4. **鳳梨酥**:這是一種受歡迎的台灣伴手禮,高雄的鳳梨酥以餡料豐富、外皮酥脆著稱。\n\n5. **草莓冰**:在夏天,草莓冰是高雄的消暑佳品,清爽的草莓搭配冰品,讓人感到清涼。\n\n6. **珍珠奶茶**:雖然珍珠奶茶在台灣各地都很流行,但高雄有許多獨特的店家,提供不同口味的珍珠奶茶。\n\n7. **豆花**:高雄的豆花口感滑嫩,常搭配花生、紅豆等配料,是一道受歡迎的甜品。\n\n這些只是高雄美食的一部分,還有許多其他美味的選擇,值得一試!'

可能需要條列的就會回應 Markdown 字串, 要用 print() 輸出才會排列整齊 : 

>>> reply=ddgs.chat(prompt)    
>>> print(reply)     
高雄是台灣的美食重鎮,擁有許多代表性的美食。以下是一些高雄的特色美食:

1. **鹽酥雞**:這道小吃在高雄的夜市非常受歡迎,外酥內嫩,搭配各種香料和調味料,口感極佳。

2. **蚵仔煎**:高雄靠近海邊,新鮮的蚵仔是這道料理的主角,搭配蛋和地瓜粉,口感滑嫩,常淋上特製醬汁。

3. **魷魚羹**:這是一道以魷魚為主料的湯品,湯頭鮮美,魷魚鮮嫩,常搭配米飯或麵條。

4. **牛肉麵**:高雄的牛肉麵以濃郁的湯頭和軟嫩的牛肉著稱,配上手工麵條,讓人一試成主顧。

5. **海鮮**:高雄的海鮮新鮮且多樣,生魚片、蒸螃蟹、烤魚等都是當地的美味選擇。

6. **草莓冰**:在炎熱的夏天,草莓冰是高雄的消暑佳品,清爽的草莓搭配冰品,讓人感到清涼。

7. **珍珠奶茶**:雖然珍珠奶茶在台灣各地都很流行,但高雄有許多獨特的店家,提供不同口味的珍珠奶茶。

8. **豆花**:高雄的豆花口感滑嫩,常搭配花生、紅豆等配料,是一道受歡迎的甜品。

這些美食只是高雄的一部分,還有許多其他美味的選擇,值得你親自去品嚐!

問它物理學的東西 :

>>> prompt='請簡單說明何謂量子糾纏?'   
>>> ddgs.chat(prompt)    
'量子糾纏是一種量子力學現象,當兩個或多個粒子以某種方式相互作用後,它們的量子狀態會變得相互依賴,即使這些粒子相隔很遠。這意味著對其中一個粒子的測量會立即影響到另一個粒子的狀態,無論它們之間的距離有多遠。\n\n簡單來說,量子糾纏使得粒子之間存在一種超越經典物理學的聯繫,這種現象挑戰了我們對於空間和時間的傳統理解。量子糾纏在量子計算和量子通信等領域具有重要的應用潛力。'

可以傳入 model 參數指定 gpt-4o-mini 模型 : 

>>> ddgs.chat(prompt, model='gpt-4o-mini')    
'量子糾纏是一種量子力學現象,當兩個或多個粒子相互作用後,它們的量子狀態會變得相互依賴。這意味著對其中一個粒子的測量會立即影響到另一個粒子的狀態,無論它們之間的距離有多遠。這種現象顯示了粒子之間存在一種超越經典物理學的聯繫,並在量子計算和量子通信等領域具有重要的應用。'

如果指定 gpt-4o 會出現錯誤, 但自動改用 gpt-4o-mini :

>>> ddgs.chat(prompt, model='gpt-4o')    
C:\Users\tony1\AppData\Local\Programs\Thonny\lib\site-packages\duckduckgo_search\duckduckgo_search.py:167: UserWarning: model='gpt-4o' is unavailable. Using 'gpt-4o-mini'
  warnings.warn(f"{model=} is unavailable. Using 'gpt-4o-mini'", stacklevel=1)
'量子糾纏是一種量子力學現象,當兩個或多個粒子相互作用後,它們的量子狀態會變得緊密相關。這意味著對其中一個粒子的測量會立即影響到另一個粒子的狀態,即使這些粒子相隔很遠。量子糾纏挑戰了我們對於空間和時間的傳統理解,並在量子計算和量子通信等領域具有重要的應用潛力。'

傳入 context 參數可以讓模型記得前後脈絡, 但下面測試卻顯示它居然記得耶 :

>>> prompt='我有養兩隻貓, 名叫小咪與萬萬'  
>>> ddgs.chat(prompt)    
'聽起來你有兩隻可愛的貓咪!小咪和萬萬的名字都很有趣。牠們的性格如何呢?有沒有什麼特別的故事或趣事可以分享?'   
>>> prompt='我那兩隻貓名字是甚麼?'   
>>> ddgs.chat(prompt)   
'你提到的兩隻貓的名字是小咪和萬萬。牠們聽起來都很可愛!如果你有任何關於牠們的問題或想分享的故事,隨時告訴我!' 
>>> prompt='你還記得我養了幾隻貓嗎? 名字是甚麼?'   
>>> ddgs.chat(prompt)   
'你養了兩隻貓,名字分別是小咪和萬萬。如果你有更多想分享的關於牠們的故事或問題,隨時告訴我!'

哇塞! 真不錯啊! 我猜 chat() 可能內建了記憶機制. 

2025年2月10日 星期一

2025 年第 6 周記事

本周六要補班, 所以週六下班後整理好才回鄉下. 過年後冰箱塞滿食材, 我週日先清出除夕祭祖的雞肉與豬肉, 雞肉做了麻油雞與蘿蔔湯; 豬肉則做了紅燒肉; 因為小舅媽又做了冬粉送來, 所以麻油雞與紅燒肉都帶來高雄當未來幾天帶便當用. 

周日早上準備 2/13 (週四) 阿蘭安金滿月日的供品, 已先向榮發舅媽訂雞豬牲禮一副 (比照掃墓不需雄雞鴨蛋魷魚, 用母雞, 雞蛋, 魚罐頭即可), 路過退伍軍人訂了發粿與紅粄, 菲膳非惡買了金香紙燭, 全聯買了水果, 只剩一對花束等週三下班去自由路買了帶回鄉下. 

週六終於收到校友證了, 但同時卻發現圖書館網站無法登入, 之前提出申請時也曾發生過, 那時打電話問, 原來是帳號被重設, 預設密碼是 nkust + 身分證末三碼, 這回卡發下來我猜也是被重設, 用之前的御設密碼果然就可以登入. 

周日下午在做紅燒肉時順便打開剛到貨的 KYNYO 收音機, 在 94.3 高雄電台剛好聽到清涼音名人開講節目, 邀請到李憲忠老師來談韓非子的人性管理, 引起了我對韓非子的興趣, 摘錄部分演講內容如下 : 
  • 人心是自利的, 法律應順應人心賞善罰惡
  • 罪刑法定主義 : 法律有明文訂定之罪刑才罰 (法無明文不罰)
  • 立法要讓人民易知易行, 可行性不高反而折損威信
  • 立法之目的 : 利民與愛民
  • 管理的方法與技巧稱為術 : 法要對人民公開 (明), 術則是御下之法, 藏在管理者心裡 (暗)
  • 管理術之四法 :
    (1). 執要 : 只管重要的, 不要事必躬親
    (2). 用人 : 勿偏聽而被蒙蔽
    (3). 參驗 : 人才需一一考察
    (4). 機智 : 我有三大死罪
  • 三部曲 : 布局, 造勢, 擺平
  • 法之三性 : 公正性, 普遍性, 強制性
  • 當主管不可與屬下太親近
聽完立馬上市圖借了好幾本談韓非子思想的書 (希望不是一頭熱, 哈哈).


2025-02-11 補充 :

今天瀏覽好學校企業版新上架課程, 赫然發現有這門課 (但我用一般版會員登入沒找到, 可能是只在企業版上架) :

# 【向韓非子學管理】探究法家思想的管理邏輯




哇! 讚讚讚, 馬上註冊, 這周末來聽聽. 

大灰熊+GP125+菁菁山葉機車強制險續保

今天辦公室清理桌面才發現大灰熊, 我的 GP125, 以及菁菁的山葉機車的保險都在過年後幾天陸續到期, 趕緊上明台網站續保 : 
  • GP125 : 強制險 2 年 + 任意險 1 年
  • 山葉機車 : 強制險 2 年 + 任意險 1 年
大灰熊還是延續給和泰, 但業務員說車齡 20 年不能保拖吊險了, 哇, 原來 QRV 已陪伴我們走過 20 年了. 

2025年2月7日 星期五

家樂福購買電腦椅

高雄家裡的電腦椅是 2022 年 9 月才買的, 使用才兩年多, 前陣子發現好像鬆鬆的會搖, 這幾天氣壓功能失效整個彈高向前傾根本無法坐, 我翻過來檢視發現是它的軸心塑膠整個裂掉所致, 所以這款 momo 賣的電腦椅不耐用 (當時買了 $1715 元), 請勿購買 :


反而是 2020 年 9 月在家樂福花了 $3280 元買的克斯電腦椅放在辦公室使用至今頭好壯壯 :


於是今日下班後去逛家樂福, 想要再買一張同款的電腦椅, 但賣場卻找不著, 詢問服務人員才知廠商會不斷改款, 以前的舊款式不會再出貨了. 無奈之餘只好就現場有的貨挑一個坐起來舒服的, 相中下面這張 $2299 元的 (但椅背不能往後打平) :





不想花時間比價了, 馬上去結帳, 店員說會員帳戶內有 500 多元點數要不要扣掉, 於是折掉後實付才 1700 多元而已. 搞定後已 8 點多了, 飢腸轆轆趕緊去一樓三商巧福點了一碗雞肉麵來吃, 看到桌上的告示才知道會員每月 3 日牛肉麵套餐有優惠價 135 元, 馬上安裝 App 加入會員 :




第一次愛的人

今年回鄉下過年時菁菁在車上播放的這首歌引起了我的興趣 : 





這首歌收錄在王心凌 2004 年的專輯 "愛你", 但是我卻毫無印象, 或許曾聽過但是忘了, 因為我以前對音樂無感, 而且我也不是王心凌的粉絲. 但現在聽到這首歌卻覺得莫名好聽.  

歌詞如下 : 

(夏天過去了, 原來這個夏天只是為了我們的相遇, 我第一次愛的人 ...)

灰色的天 你的臉
愛過也哭過笑過痛過之後只剩再見
我的眼淚 溼了臉
失去第一次愛的人竟然是這種感覺
總以為 愛是全部的心跳
失去愛我們就要 就要 一點點慢慢的死掉
當我 失去你那一秒 心突然就變老
The Day You Went Away
喧鬧的街 沒發現我的淚 被遺忘在街角
The Day You Went Away

我看著你 走過街
還穿著去年夏天我送你的那雙球鞋
銀色手鍊 還耀眼
你的世界似乎一點也沒有因此改變
總以為 愛是全部的心跳
失去愛我們就要 就要 一點點慢慢的死掉
當我 失去你那一秒 心突然就變老
The Day You Went Away
喧鬧的街 沒發現我的淚 被遺忘在街角
The Day You Went Away (The Day You Went Away)
The Day You Went Away

WO WO WO~總以為 愛是全部的心跳
失去愛我們就要 就要 一點點慢慢的死掉
當我 失去你那一秒 心突然就變老
The Day You Went Away
喧鬧的街 沒發現我的淚 被遺忘在街角
The Day You Went Away
有一天也許我能把自己治好
再一次想起來 應該要怎麼笑
第一次愛的人 它的壞他的好
卻像胸口刺青 是永遠的記號
跟著我的呼吸 直到停止心跳

(作詞:林怡芬  作曲:Marit Elizabeth, Marion Elise Ravn)

第一次失戀不管有多傷心, 在多年以後回頭看, 都會覺得那時好真也好傻. 

2025年2月5日 星期三

市圖還書 3 本 (AI繪圖夢工廠 + 量子電腦程式設計等)

過年前市圖將所有連假期間的到期書全部改為今天到期, 下面三本有人預約須還 : 
No.1 借了兩個月都沒時間看, 殘念. 另外兩本量子計算的也是, 去年內訓之後興致勃勃借來, 但手上要忙的東西很多, 根本輪不到量子計算, 唉, 只能嘆學海無涯.

2025年2月3日 星期一

2025 年第 5 周記事

9 天春節假期終於在昨天畫下句點, 今天收假上班了. 今年過年行程簡單紀錄如下 :

除夕 : 早上貼紅紙春聯, 下午祭祖, 晚上吃薑母鴨火鍋
春節 : 早上拜廟, 中午繼續吃薑母鴨火鍋, 晚上吃麥當勞
初二 : 早上包水餃, 整天宅在家看韓劇, 晚上繼續吃水餃
初三 : 回娘家, 中午烤肉吃麻油雞, 晚上下廚

這個年假我只在年初三晚上因為菁菁的朋友來訪下廚一次而已, 感覺好輕鬆, 以後過年就照此 SOP 吧! 但是我的廚藝也會退步, 哈哈. 

由於姐姐買到年初四早上的高鐵票, 所以年初三吃過晚餐我們就先回高雄了, 初四早上載姐姐去坐高鐵回來馬上又跟水某坐捷運去前鎮琪大師家與大帥仲仔聚會, 暢聊了一整個下午, 度過美好的一天. 

初四晚上去楠梓接菁菁下班, 因為她年初五 (周日) 休息, 下午四點去自由路大中路口的小時厚牛排吃飯 (姊姊回台北了沒吃到), 因為每個周日晚上我從鄉下回高雄路過這裡看到客人還很多, 好奇到底是多好吃啊? 就想說找一天來吃看看, 今日品嘗後覺得主食 (牛排, 雞排, 魚排, 豬排等) 比達樂斯好吃, 但達樂斯有羅宋湯, 酥皮濃湯, 沙拉吧, 水果等我覺得 CP 值稍高. 菁菁沒吃過達樂斯, 下次帶她去吃看看後再來聽聽她的評價. 

Mapleboard MP510-50 測試 (二十三) : 安裝 Anydesk (成功)

昨天春節連假收假最後一天時間都花在調校 Mapleboard, 完成防火牆設定後 PuTTY SSH 已可連線, 但 VNC Server 設定有問題, 雖可成功直連但桌面卻只出現 xterm 視窗, 沒有出現完整 X 視窗, 所以目前遠端桌面還是只能依賴 RealVNC Cloud.

整理筆記發現以前安裝 Anydesk 失敗那篇底下有網友留言在 Mapleboard 上成功安裝了 Anydesk, 抱著姑且一試的心情, 開啟 Mapleboard 的 Firefox 連線到 Anydesk 官網, 它會偵測作業系統自動切到 Linux (Ubuntu) 的下載頁面, 不要按 "立即下載" 鈕, 這會下載 Ubuntu 版本 (amd64), 安裝會出現錯誤, 要按底下 Raspberry Pi 按鈕下載樹莓派版本 (arm64) : 





開啟檔案管理員切換到 '下載' 資料夾, 雙擊 arm64 版本的 deb 檔執行安裝 :





安裝完畢後在 "選單/網際網路" 選單中就會出現 "Anydesk" 了 :




點擊執行 Anydesk : 





按 "設定無人值守密碼" : 




勾選 "啟用無人值守存取" 後按 "設定無人值守存取密碼" :




設定密碼後關閉視窗即可 :




至此即完成 Anydesk 安裝設定, 重新啟動 Mapleboard 會自動執行 Anydesk. 

然後用我的 LG 筆電內的 Anydesk 連線 Mapleboard 的 ID 位址 :




經過密碼驗證後終於出現 Ubuntu Mate 桌面 :




預設桌面似乎太小, 按正上方的顯示器按鈕, 點選 "延伸" 即可放大桌面 :





在上次安裝失敗的兩年後終於把 Anydesk 搞定了. 

2025年2月2日 星期日

Mapleboard MP510-50 測試 (二十二) : 安裝 ufw 防火牆

由於 Hinet 年初更換了我的光世代固定 IP, 趁過年期間將 Mapleboard 主機重開機取得新的固定 IP 後到 Namecheap 將 tony1966.cc 域名綁定到新的固定 IP 恢復了此域名的運作, 接下來要安裝 ufw 防火牆來加強主機安全性, 做法參考 :


本系列測試文章參考 : 



1. 啟用 ufw 防火牆 : 

ufw 是 Uncomplicated FireWall 的縮寫, 具有指令簡單好記, 設定規則淺顯易懂優點, Ubuntu 通常已預設安裝 ufw, 可用下列指令查看防火牆狀態 :
 
sudo ufw status   

one@LX2438:~$ sudo ufw status   
[sudo] one 的密碼: 
狀態:不活動  (inactive)

Inactive 狀態表示雖然 ufw 已安裝卻尚未啟用, 須使用下列指令啟用 (activate) :

sudo ufw enable   

tony1966@LX2438:~$ sudo ufw enable   
[sudo] tony1966 的密碼: 
在系統啟動時啟用防火牆   

在下次啟動時才會啟用 ufw 防火牆. 這時再次檢視防火牆狀態會顯示已啟用 (active) :

tony1966@LX2438:~$ sudo ufw status       
狀態: 啓用   

若執行上述指令出現未找到 ufw 錯誤, 表示系統尚未安裝 ufw (例如屬於 Debian 系統的樹莓派預設並未安裝 ufw), 要先用下列指令安裝 : 

udo apt-get install ufw    


2. 設定防火牆規則

下列指令會顯示目前的防火牆規則 : 

sudo ufw status verbose

tony1966@LX2438:~$ sudo ufw status verbose    
[sudo] tony1966 的密碼: 
狀態: 啓用
日誌: on (low) 
Default: deny (incoming), allow (outgoing), disabled (routed)
新建設定檔案: skip

可見 ufw 預設會拒絕所有進入主機的連線, 但允許所有出去的連線; 預設關閉封包轉送功能 (作為路由器與 VPN 時才需要打開). 日誌功能已開啟, 紀錄等級預設為 low (等級有五個等級 : off/low/medium/high/full), 可用下列指令更改等級 :

sudo ufw logging medium    

如果要更改預設規則可用下列指令 : 

sudo ufw default allow   (不安全, 不建議)
sudo ufw default deny    (較安全, 預設)

接下來要設定主機的允入連線埠號, 由於我這台 Mapleboard MP510-50 主機主要是作為網頁伺服器與 API 測試之用, 因此只要開啟 TCP 協定的埠口即可, UDP 目前用不到不需要開啟. 未來如果要做 DNS 伺服器 (53 埠), NTP 伺服器 (123 埠), 或 VPN 伺服器 (OpenVPN 1194 埠) 等用途再開啟各埠之 UDP. 

首先是埠號 22 的 ssh 遠端連線服務 : 

sudo ufw allow ssh/tcp  或 sudo ufw allow 22/tcp   

tony1966@LX2438:~$ sudo ufw allow 22/tcp       
[sudo] tony1966 的密碼: 
已添加規則
已添加規則 (v6)
 
埠號 80 的 HTTP 連線是作為網頁伺服器主機一定要開啟此埠 :

sudo ufw allow 80/tcp   

tony1966@LX2438:~$ sudo ufw allow 80/tcp   
已添加規則
已添加規則 (v6)

埠號 443 的 HTTPS 連線也是作為網頁伺服器主機一定要開啟的埠號 (雲端的遠端連線服務 RealVNC Cloud 也是透過 443 埠連線) :

sudo ufw allow 443/tcp  

tony1966@LX2438:~$ sudo ufw allow 443/tcp     
已添加規則
已添加規則 (v6)

另外直連的 VNC 使用 5900/5901 埠 (TCP) 也要打開 :  

sudo ufw allow 5900/tcp    

tony1966@LX2438:~$ sudo ufw allow 5900/tcp    
已添加規則
已添加規則 (v6)

tony1966@LX2438:~$ sudo ufw allow 5901/tcp   
[sudo] tony1966 的密碼: 
已添加規則
已添加規則 (v6)

顯示目前的防火牆規則 : 

tony1966@LX2438:~$ sudo ufw status verbose   
狀態: 啓用
日誌: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
新建設定檔案: skip

至                          動作          來自
-                          --          --
22/tcp                     ALLOW IN    Anywhere                  
80/tcp                     ALLOW IN    Anywhere                  
443/tcp                    ALLOW IN    Anywhere                  
5900/tcp                   ALLOW IN    Anywhere                  
5901/tcp                   ALLOW IN    Anywhere                  
22/tcp (v6)                ALLOW IN    Anywhere (v6)             
80/tcp (v6)                ALLOW IN    Anywhere (v6)             
443/tcp (v6)               ALLOW IN    Anywhere (v6)             
5900/tcp (v6)              ALLOW IN    Anywhere (v6)             
5901/tcp (v6)              ALLOW IN    Anywhere (v6)     

如果要刪除規則重新設定, 要先用下列指令查詢規則編號 :

sudo ufw status numbered  

tony1966@LX2438:~$ sudo ufw status numbered    
狀態: 啓用

     至                          動作          來自
     -                          --          --
[ 1] 22/tcp                     ALLOW IN    Anywhere                  
[ 2] 80/tcp                     ALLOW IN    Anywhere                  
[ 3] 443/tcp                    ALLOW IN    Anywhere                  
[ 4] 5900/tcp                   ALLOW IN    Anywhere                  
[ 5] 5901/tcp                   ALLOW IN    Anywhere                  
[ 6] 22/tcp (v6)                ALLOW IN    Anywhere (v6)             
[ 7] 80/tcp (v6)                ALLOW IN    Anywhere (v6)             
[ 8] 443/tcp (v6)               ALLOW IN    Anywhere (v6)             
[ 9] 5900/tcp (v6)              ALLOW IN    Anywhere (v6)             
[10] 5901/tcp (v6)              ALLOW IN    Anywhere (v6)             

然後以下列指令刪除指定編號之規則 :

sudo ufw delete 規則編號     

tony1966@LX2438:~$ sudo ufw delete 1    
刪除中:
 allow 22/tcp
 繼續執行(y|n)? y
已刪除規則 (v6)

如果想要全部重設, 可用下列指令 :

sudo ufw reset 

防火牆規則設定好後毋須重開機, 只要用下列指令重新載入即可 :

sudo ufw reload   

tony1966@LX2438:~$ sudo ufw reload   
已經重新載入防火牆


3. 使用應用程式設定防火牆規則 : 

除了上面利用 port/protocol 方式設定防火牆規則外, 也可以用應用程式名稱來設定, 先用下面指令顯示 ufw 預設的應用程式列表 : 

sudo ufw app list   

one@LX2438:~$ sudo ufw app list    
[sudo] one 的密碼: 
可用套用程序:
  CUPS
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

我們可以直接用這些應用名稱來設定其防火牆規則, 不用手動輸入連接埠號碼.

首先用下列指令查詢應用程式的描述 : 

sudo ufw app info "應用程式名稱"   

例如 : 

tony1966@LX2438:~$ sudo ufw app info "Nginx Full"      
設定: Nginx Full
標題:Web Server (Nginx, HTTP + HTTPS)
描述: Small, but very powerful and efficient web server

tony1966@LX2438:~$ sudo ufw app info "Nginx HTTP"     
設定: Nginx HTTP
標題:Web Server (Nginx, HTTP)
描述: Small, but very powerful and efficient web server

埠號:
  80/tcp
tony1966@LX2438:~$ sudo ufw app info "Nginx HTTPS"    
設定: Nginx HTTPS
標題:Web Server (Nginx, HTTPS)
描述: Small, but very powerful and efficient web server

埠號:
  443/tcp
tony1966@LX2438:~$ sudo ufw app info "OpenSSH"   
設定: OpenSSH
標題:Secure shell server, an rshd replacement
描述: OpenSSH is a free implementation of the Secure Shell protocol.

埠號:
  22/tcp
tony1966@LX2438:~$ sudo ufw app info "CUPS"   
設定: CUPS
標題:Common UNIX Printing System server
描述: CUPS is a printing system with support for IPP, samba, lpd, and other
protocols.

如果使用應用程式名稱來設定防火牆規則只要用下列兩個指令即可, 做用與上面指定埠號/協定之效果一樣 :

sudo ufw allow "OpenSSH"       # 開啟 SSH
sudo ufw allow "Nginx Full"    # 開啟 HTTP 和 HTTPS

第一個指令相當於 sudo ufw allow 22/tcp; 第二個指令相當於 sudo ufw allow 80/tcp 與 sudo ufw allow 443/tcp. 


4. 檢視 ufw 防火牆日誌 : 

防火牆日誌檔放在 /var/log 下的 ufw.log, 可以用 less 指令按上下鍵一列一列瀏覽 (輸入 q 跳出) :

sudo less /var/log/ufw.log    




我擷取了一部分 log 請 ChatGPT 說明如下 :

🔹 Feb 4 08:40:43 → 記錄發生的時間
🔹 LX2438 → 你的主機名稱
🔹 kernel: → 這是來自 Linux 核心的訊息
🔹 [UFW BLOCK] → 這表示 UFW 防火牆封鎖了這個封包
🔹 IN=ppp0 → 這個封包來自 ppp0(你的撥接網路介面)
🔹 OUT= → 空白,代表這個封包沒有要轉發到其他網路介面
🔹 SRC=195.230.103.249 → 封包來源 IP(可疑來源)
🔹 DST=1xx.xxx.xxx.x2 → 你的主機 IP(目標 IP)
🔹 LEN=40 → 封包長度(40 bytes)
🔹 PROTO=TCP → 傳輸協定(這是 TCP 封包)
🔹 SPT=50878 → 來源埠(50878,這是動態隨機埠)
🔹 DPT=52217 → 目標埠(52217,通常是隨機端口,可能是掃描攻擊)
🔹 WINDOW=65535 → TCP 視窗大小(這是典型的 TCP 參數)
🔹 RES=0x00 → 預留欄位(一般無特別意義)
🔹 SYN → 這是 SYN 封包(表示有人嘗試建立 TCP 連線)
🔹 URGP=0 → 緊急指標(通常為 0,表示非緊急封包)

這些 log 顯示這些封包可能是惡意掃描或試圖入侵, 但 ufw 防火牆已阻擋了這些試圖連入主機的外部 IP. 目標埠 DPT=81 的連線可能是自動化掃描工具正在尋找開放的 Web 服務 (81 是 HTTP 常用的替代埠號), DPT=8081 表示有人試圖存取 API 或 Web 管理介面 (8081 通常是 HTTP 代理伺服器或管理介面); 而隨機埠 (例如 21804, 1039) 則可能是惡意掃描工具嘗試連線.

如果要連續監看即時的防火牆 log 可用下列指令 :

sudo tail -f /var/log/ufw.log    

此時終端機會被此程序占用, 欲停止監看可按 Ctrl + c (注意是小寫).

如果只想檢視最近幾筆日誌可用 tail 指令, 例如查看最近 50 筆 : 

sudo tail -n 50 /var/log/ufw.log      

可以搭配 grep 指令過濾日誌, 例如過濾最近 20 筆 SSH (22 埠) 連線 :

sudo grep "DPT=22 " /var/log/ufw.log | tail -n 20    

注意 22 後面要加一個空格才不會抓到 22 開頭的埠號. 

或者來自特定 IP 的連線 : 

sudo grep "189.144.115.217" /var/log/ufw.log | tail -n 20   

以上 ufw 指令摘要如下表 : 


 ufw 指令  說明
 sudo ufw enable  啟用 ufw 防火牆
 sudo ufw disable  停用 ufw 防火牆
 sudo ufw status  檢查防火牆狀態
 sudo ufw status verbose  顯示詳細的防火牆狀態
 sudo ufw allow 22/tcp  允許 SSH ( 22 埠 / TCP )
 sudo ufw deny 80/tcp  拒絕 HTTP ( 80 埠 / TCP )
 sudo ufw allow from 192.168.1.100  允許來自 192.168.1.100 的所有連線
 sudo ufw delete allow 22/tcp  刪除允許 SSH 的規則
 sudo ufw reset  重設 ufw 設定,回復到預設狀態
 sudo ufw reload  重新載入防火牆規則


參考 :