Skip to content

Instantly share code, notes, and snippets.

@nperovic
Last active March 29, 2025 22:18
Show Gist options
  • Save nperovic/17c544cb43629fca5e8f5ea8c40190d3 to your computer and use it in GitHub Desktop.
Save nperovic/17c544cb43629fca5e8f5ea8c40190d3 to your computer and use it in GitHub Desktop.
透過 AHK v2.1 調用 Gemini API
/************************************************************************
* @description 調用 Gemini API 的函式。
* @author Nikola Perovic
* @link https://gist.github.com/nperovic/17c544cb43629fca5e8f5ea8c40190d3
* @date 2025/03/30
* @version 1.0.0
***********************************************************************/
#Requires AutoHotkey 2.1-alpha.18
; https://github.com/G33kDude/cJson.ahk
#Include <cJSON>
/**
* 調用 Gemini API 發送請求並取得回應。支援自動偵測及處理 YouTube 連結。
*
* ### 必要條件
* 1. 需要設定 `GEMINI_API_KEY` 環境變數:
* - 搜尋「環境變數」在系統設定中
* - 編輯「使用者變數」(目前使用者) 或「系統變數」(所有使用者)
* - 新增變數名稱 `GEMINI_API_KEY`
* - 變數值設為: `export GEMINI_API_KEY = your_key_here`
* - 套用變更
*
* ### 注意事項
* - 一次只能包含一個 YouTube 連結,超過會拋出錯誤
* - YouTube 連結會自動從提示詞中移除並放入檔案參數
* - 目前不支援傳回 `gemini-2.0-flash-exp` 生成的圖片
*
*
* @param {String} userPrompt 使用者提示詞,可包含一個 YouTube 連結
* @param {String} [systemPrompt=""] 系統提示詞,用於設定 AI 的行為準則
* @param {String} [model="gemini-2.0-flash"] 模型名稱
* 支援的模型請參考: {@link https://ai.google.dev/gemini-api/docs/models 官方文件}
* @param {Number} [temperature=0.3] 控制輸出的隨機性,範圍 0-2
* - 0: 最確定的輸出
* - 1: 平衡的輸出
* - 2: 最具創意的輸出
* @throws {ValueError} 當溫度參數超出 0-2 範圍時
* @throws {Error} 當包含多個 YouTube 連結或 API 請求失敗時
* @return {String} API 回應的文本內容
* @link https://ai.google.dev/gemini-api/docs
* @example
* ; 基本使用
* response := CallGemini("分析這段文字")
*
* ; 使用 YouTube 分析
* response := CallGemini("分析這個影片: https://youtu.be/abc123")
*
* ; 使用系統提示詞和自定義溫度
* response := CallGemini(
* "你們到底為什麼這麼反 AI 啊?",
* "將使用者傳送的所有內容以 Reddit 網友風格的美式英文改寫,要精準傳達原意,且用詞自然、口語化。 **只要回傳改寫結果。**",
* "gemini-2.0-flash-lite",
* 0.2
* )
*/
CallGemini(userPrompt, systemPrompt := "", model := "gemini-2.0-flash", temperature :=
0.3)
{
static apikey := RegExReplace(EnvGet("GEMINI_API_KEY"), "Si)^.+=")
static ytRegex :=
"isS)((?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)(?:[a-zA-Z0-9_-]{11}\/?))"
if temperature < 0 || temperature > 2
throw ValueError("溫度參數必須在 0 與 2 之間")
endpoint := "https://generativelanguage.googleapis.com/v1beta/models/" model ":generateContent?key=" apikey
jsonObj := {
contents: [
{
role : "user",
parts: []
}
],
generationConfig: {
temperature : String(temperature),
topP : "0.95",
topK : "40",
maxOutputTokens : InStr(model, "think") ? "65535": "8192",
responseMimeType: "text/plain"
}
}
ytURL := ""
userPrompt := RegExReplace(userPrompt, ytRegex, (m) => ytURL := m[], &mCount)
jsonObj.contents[1].parts.Push({
text: userPrompt
})
if mCount > 1
Throw Error("只能包含一個 YouTube 連結")
else if mCount = 1
jsonObj.contents[1].parts.Push({
file_data: {
file_uri: ytURL
}
})
; 添加系統提示詞(如有)
if systemPrompt
jsonObj.systemInstruction := {
parts: [
{
text: systemPrompt
}
]
}
reqBody := cJSON.Dump(jsonObj, 1)
; 創建 HTTP 請求
req := ComObject("WinHttp.WinHttpRequest.5.1")
req.Open("POST", endpoint, true)
req.SetRequestHeader("Content-Type", "application/json")
req.Send(reqBody)
req.WaitForResponse()
if req.status = 200 {
response := cJSON.Load(req.ResponseText)
try return response['candidates'][1]['content']['parts'][1]['text']
throw Error("無法從回應中提取文本內容")
}
else {
errorMsg := "API 請求失敗,狀態碼: " req.Status
try {
errorResp := cJSON.Load(req.ResponseText)
if errorResp.HasOwnProp("error") && errorResp.error.HasOwnProp("message")
errorMsg .= "`n錯誤訊息: " errorResp.error.message
}
throw Error(errorMsg)
}
return ""
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment