Last active
March 29, 2025 22:18
-
-
Save nperovic/17c544cb43629fca5e8f5ea8c40190d3 to your computer and use it in GitHub Desktop.
透過 AHK v2.1 調用 Gemini API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************ | |
* @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