Raycast 內建 AI,能使用不少模型。網路上有兩個很好用的專案,可以把它轉成 OpenAI 相容 API,讓其他用戶端也能直接使用。一個是 raycast-relay,另一個是 missuo 的 raycast2api,我之前一直在用。但 Raycast 更新後,這兩個專案都不能用了。原因是新版請求多了一個簽章,沒有它就無法通過。其中 raycast-relay 已經封存,不再維護,所以我乾脆自己動手,逆向分析新的簽章,重新寫了一個,名字沿用 raycast2api,程式碼放在 xxxbrian/raycast2api。它做了什麼整個專案其實只做一件事:把 OpenAI 格式的請求轉成 Raycast 的請求,再把 Raycast 的回應轉回來。對外只有幾個端點。端點用途GET /v1/models模型清單POST /v1/chat/completions對話,支援串流與非串流GET /health存活檢查GET /ready就緒檢查模型清單每次都會向 Raycast 取得,所以 Raycast 新增模型時,這邊不需要修改。取得後,我會依環境變數篩選一次:ADVANCED 控制是否包含進階模型,INCLUDE_DEPRECATED 控制是否包含已棄用的模型。對話的轉換也不複雜。OpenAI 訊息清單開頭的 system 訊息會變成 Raycast 的 system_instruction,user 和 assistant 訊息則轉成 Raycast 的 author 加上 content.text 格式。請求中的模型 ID 會用來查詢模型清單,找出對應的 provider 和內部模型名稱,每次請求也會產生新的 thread_id。Raycast 回傳的是 SSE,每一行 data: 帶著一小段文字和結束標記。串流時,我把每一段重新包成 OpenAI 的 chat.completion.chunk 傳出去,最後補上 [DONE]。非串流時,則把所有文字接起來,一次回傳。因為 Raycast 不提供 token 用量,非串流回應的 usage 暫時填 0,串流回應則不提供用量統計。V2 簽章新版 Raycast 請求除了原有的 Authorization 和 X-Raycast-DeviceId,還多了 X-Raycast-Timestamp 和 X-Raycast-Signature-v2。前幾項都好處理,只有最後的簽章需要自己算出來。簽章過程其實只有幾步。先對請求主體計算 SHA-256,再把時間戳記、裝置 ID 和這個雜湊值各自做一次 ROT13 加 ROT5 編碼,也就是字母以 ROT13 轉換,數字以 ROT5 轉換,其餘字元不變。接著用 . 串起這三段,最後以金鑰計算 HMAC-SHA256,得到的十六進位結果就是簽章。時間戳記和裝置 ID 都參與簽章,所以每次請求的簽章都不同,裝置 ID 也與請求綁在一起。專案內有預設金鑰,之後若有變更,也能透過 RAYCAST_SIGNATURE_SECRET 環境變數覆寫。這裡全部使用 Web Crypto API,所以同一份程式碼在 Workers 和 Bun 都能執行,不需要額外相依套件。一份程式碼,三種部署方式我想讓這個專案盡量容易部署。有人習慣 Cloudflare Workers,有人比較喜歡 Docker,也有人只想在自己的電腦上跑一下,所以這三種方式我都想支援。幸好 Hono 本來就是跨執行環境的框架,同一個 app 可以直接當作 Worker 的進入點,也能交給 Bun.serve。環境變數同樣透過 Hono 的 env() 讀取,在哪個執行環境裡,寫法都一樣。Cloudflare Workers進入點是 src/index.ts,wrangler.jsonc 只寫了名稱和進入點檔案。README 裡放了一個 Deploy to Cloudflare Workers 按鈕,點一下就能部署,再到後台填上環境變數。Dockerserver.ts 只有幾行,把 Hono 的 app.fetch 交給 Bun.serve,連接埠預設為 3000。Dockerfile 分成兩個階段:第一階段用 bun build --compile 編譯成獨立的可執行檔,第二階段把它複製到 debian:bookworm-slim,所以最後的映像檔裡只有一個二進位執行檔。BASH複製docker run -d \ --name raycast2api \ -p 3000:3000 \ -e RAYCAST_BEARER_TOKEN=your-raycast-bearer-token \ -e RAYCAST_DEVICE_ID=your-raycast-device-id \ -e API_KEY=your-api-key \ ghcr.io/xxxbrian/raycast2api:latest發布 Release 時,GitHub Actions 會自動建置映像檔並推送到 ghcr.io,同時支援 linux/amd64 和 linux/arm64。部署到 Kubernetes 時,可以把 /health 當作存活探針,/ready 當作就緒探針。前者只檢查設定是否齊全;後者除了檢查設定,也會確認最近向 Raycast 發出的請求是否正常。不正常時,會嘗試取得一次模型清單,確認 Raycast 是否連得上。這項檢查最多每 30 秒執行一次。Note這一版的健康探針會直接檢查是否已設定 RAYCAST_SIGNATURE_SECRET。即使簽章邏輯本身有預設值,使用探針時仍須明確設定這一項。二進位執行檔Docker 使用的編譯指令,只要換個 --target 就能編譯出不同平台的版本。所以發布 Release 時,Actions 會分別編譯 Linux、macOS、Windows 的 x64 和 arm64 版本,只有 Windows arm64 不在其中,最後再把產物上傳到 Release。下載後直接執行即可,不必安裝任何執行環境。憑證執行前需要兩個值:RAYCAST_BEARER_TOKEN 和 RAYCAST_DEVICE_ID。兩者都能從 Raycast 自己發出的請求取得:使用 Proxyman 或 Charles 之類的封包擷取工具,對 backend.raycast.com 開啟 SSL 代理,再到 Raycast 隨便送出一則 AI 對話,就能在請求標頭看到 Authorization: Bearer ... 和 X-Raycast-DeviceId。Warning這兩個值等同於你自己的 Raycast 帳號,千萬別外洩。沒有設定 API_KEY 時,部署後的 API 會對所有人開放,別人也能用你的帳號呼叫。建議務必設定;用戶端把它當作 OpenAI 的 API Key 使用即可。使用部署好後,在任何支援自訂 OpenAI 位址的用戶端,把 Base URL 填成部署位址,API Key 填入自己設定的 API_KEY,就能直接選擇模型對話。
Raycast 內建 AI,能使用不少模型。網路上有兩個很好用的專案,可以把它轉成 OpenAI 相容 API,讓其他用戶端也能直接使用。一個是 raycast-relay,另一個是 missuo 的 raycast2api,我之前一直在用。
但 Raycast 更新後,這兩個專案都不能用了。原因是新版請求多了一個簽章,沒有它就無法通過。其中 raycast-relay 已經封存,不再維護,所以我乾脆自己動手,逆向分析新的簽章,重新寫了一個,名字沿用 raycast2api,程式碼放在 xxxbrian/raycast2api。
它做了什麼
整個專案其實只做一件事:把 OpenAI 格式的請求轉成 Raycast 的請求,再把 Raycast 的回應轉回來。對外只有幾個端點。
端點
用途
GET /v1/models
模型清單
POST /v1/chat/completions
對話,支援串流與非串流
GET /health
存活檢查
GET /ready
就緒檢查
模型清單每次都會向 Raycast 取得,所以 Raycast 新增模型時,這邊不需要修改。取得後,我會依環境變數篩選一次:ADVANCED 控制是否包含進階模型,INCLUDE_DEPRECATED 控制是否包含已棄用的模型。
對話的轉換也不複雜。OpenAI 訊息清單開頭的 system 訊息會變成 Raycast 的 system_instruction,user 和 assistant 訊息則轉成 Raycast 的 author 加上 content.text 格式。請求中的模型 ID 會用來查詢模型清單,找出對應的 provider 和內部模型名稱,每次請求也會產生新的 thread_id。
Raycast 回傳的是 SSE,每一行 data: 帶著一小段文字和結束標記。串流時,我把每一段重新包成 OpenAI 的 chat.completion.chunk 傳出去,最後補上 [DONE]。非串流時,則把所有文字接起來,一次回傳。因為 Raycast 不提供 token 用量,非串流回應的 usage 暫時填 0,串流回應則不提供用量統計。
V2 簽章
新版 Raycast 請求除了原有的 Authorization 和 X-Raycast-DeviceId,還多了 X-Raycast-Timestamp 和 X-Raycast-Signature-v2。前幾項都好處理,只有最後的簽章需要自己算出來。
簽章過程其實只有幾步。先對請求主體計算 SHA-256,再把時間戳記、裝置 ID 和這個雜湊值各自做一次 ROT13 加 ROT5 編碼,也就是字母以 ROT13 轉換,數字以 ROT5 轉換,其餘字元不變。接著用 . 串起這三段,最後以金鑰計算 HMAC-SHA256,得到的十六進位結果就是簽章。
時間戳記和裝置 ID 都參與簽章,所以每次請求的簽章都不同,裝置 ID 也與請求綁在一起。專案內有預設金鑰,之後若有變更,也能透過 RAYCAST_SIGNATURE_SECRET 環境變數覆寫。
這裡全部使用 Web Crypto API,所以同一份程式碼在 Workers 和 Bun 都能執行,不需要額外相依套件。
一份程式碼,三種部署方式
我想讓這個專案盡量容易部署。有人習慣 Cloudflare Workers,有人比較喜歡 Docker,也有人只想在自己的電腦上跑一下,所以這三種方式我都想支援。
幸好 Hono 本來就是跨執行環境的框架,同一個 app 可以直接當作 Worker 的進入點,也能交給 Bun.serve。環境變數同樣透過 Hono 的 env() 讀取,在哪個執行環境裡,寫法都一樣。
Cloudflare Workers
進入點是 src/index.ts,wrangler.jsonc 只寫了名稱和進入點檔案。README 裡放了一個 Deploy to Cloudflare Workers 按鈕,點一下就能部署,再到後台填上環境變數。
Docker
server.ts 只有幾行,把 Hono 的 app.fetch 交給 Bun.serve,連接埠預設為 3000。Dockerfile 分成兩個階段:第一階段用 bun build --compile 編譯成獨立的可執行檔,第二階段把它複製到 debian:bookworm-slim,所以最後的映像檔裡只有一個二進位執行檔。
發布 Release 時,GitHub Actions 會自動建置映像檔並推送到 ghcr.io,同時支援 linux/amd64 和 linux/arm64。部署到 Kubernetes 時,可以把 /health 當作存活探針,/ready 當作就緒探針。前者只檢查設定是否齊全;後者除了檢查設定,也會確認最近向 Raycast 發出的請求是否正常。不正常時,會嘗試取得一次模型清單,確認 Raycast 是否連得上。這項檢查最多每 30 秒執行一次。
這一版的健康探針會直接檢查是否已設定 RAYCAST_SIGNATURE_SECRET。即使簽章邏輯本身有預設值,使用探針時仍須明確設定這一項。
二進位執行檔
Docker 使用的編譯指令,只要換個 --target 就能編譯出不同平台的版本。所以發布 Release 時,Actions 會分別編譯 Linux、macOS、Windows 的 x64 和 arm64 版本,只有 Windows arm64 不在其中,最後再把產物上傳到 Release。下載後直接執行即可,不必安裝任何執行環境。
憑證
執行前需要兩個值:RAYCAST_BEARER_TOKEN 和 RAYCAST_DEVICE_ID。兩者都能從 Raycast 自己發出的請求取得:使用 Proxyman 或 Charles 之類的封包擷取工具,對 backend.raycast.com 開啟 SSL 代理,再到 Raycast 隨便送出一則 AI 對話,就能在請求標頭看到 Authorization: Bearer ... 和 X-Raycast-DeviceId。
這兩個值等同於你自己的 Raycast 帳號,千萬別外洩。沒有設定 API_KEY 時,部署後的 API 會對所有人開放,別人也能用你的帳號呼叫。建議務必設定;用戶端把它當作 OpenAI 的 API Key 使用即可。
使用
部署好後,在任何支援自訂 OpenAI 位址的用戶端,把 Base URL 填成部署位址,API Key 填入自己設定的 API_KEY,就能直接選擇模型對話。