Last active
December 4, 2024 02:19
-
-
Save kujirahand/86e6f182d1ed0232f5c1c9fdeff7ea79 to your computer and use it in GitHub Desktop.
FPC for ChatGPT Simple Unit (for Windows) プロジェクト全体はこちら→ https://kujirahand.com/blog/go.php?822
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
| unit ChatGPTUnit; | |
| {$mode ObjFPC}{$H+} | |
| interface | |
| uses | |
| fpjson, jsonparser, Process, Classes, SysUtils; | |
| function CallChatGPTAPI(const Prompt: string): string; | |
| function ParseChatGPTResponse(const json: string): string; | |
| function ProcessExecuteHide(const AExecutable: string; const AParameters: array of string): Integer; | |
| function LoadFromFile(FName: string): string; | |
| procedure SaveToFile(FName: string; Body: string); | |
| implementation | |
| const | |
| API_URL = 'https://api.openai.com/v1/chat/completions'; | |
| ENV_API_KEY = 'OPENAI_API_KEY'; // 環境変数の名前 | |
| MODEL_NAME = 'gpt-4o-mini'; // 使用するモデル | |
| // テキストファイルを読む | |
| function LoadFromFile(FName: string): string; | |
| var sl: TStringList; | |
| begin | |
| sl := TStringList.Create; | |
| sl.LoadFromFile(FName); | |
| Result := sl.Text; | |
| sl.Free; | |
| end; | |
| // テキストファイルに書き込む | |
| procedure SaveToFile(FName: string; Body: string); | |
| var sl: TStringList; | |
| begin | |
| sl := TStringList.Create; | |
| sl.Text := Body; | |
| sl.SaveToFile(Fname); | |
| sl.Free; | |
| end; | |
| // ChatGPTへ問い合わせる | |
| function CallChatGPTAPI(const Prompt: string): string; | |
| var | |
| APIKey, cmd, curl, apppath: string; | |
| ctype, auth, body, batfile, jsonfile: string; | |
| JsonRequest: TJSONObject; | |
| resfile, response: string; | |
| begin | |
| // 環境変数からAPIキーを取得 | |
| APIKey := GetEnvironmentVariable(ENV_API_KEY); | |
| if APIKey = '' then | |
| begin | |
| Result := '環境変数でAPIキーを設定してください'; | |
| Exit; | |
| end; | |
| // バッチファイルを生成するために一時ファイルのパスを決める | |
| apppath := ExtractFilePath(ParamStr(0)); | |
| curl := ConcatPaths([apppath, 'curl.exe']); | |
| batfile := ConcatPaths([apppath, 'request.bat']); | |
| resfile := ConcatPaths([apppath, 'response.txt']); | |
| jsonfile := ConcatPaths([apppath, 'request.json']); | |
| if not FileExists(curl) then curl := 'curl'; // デフォルトのcurlを使う | |
| try | |
| // リクエストJSON作成 | |
| JsonRequest := TJSONObject.Create; | |
| try | |
| JsonRequest.Add('model', MODEL_NAME); | |
| JsonRequest.Add('messages', TJSONArray.Create([ | |
| TJSONObject.Create(['role', 'user', 'content', Prompt]) | |
| ])); | |
| JsonRequest.Add('temperature', 0.7); | |
| SaveToFile(jsonfile, JsonRequest.AsJSON); | |
| finally | |
| JsonRequest.Free; | |
| end; | |
| ctype := 'Content-Type: application/json'; | |
| auth := 'Authorization: Bearer ' + APIKey; | |
| cmd := Format('"%s" %s -H "%s" -H "%s" -d @"%s" > "%s"', [ | |
| curl, API_URL, ctype, auth, jsonfile, resfile]); | |
| // バッチファイルに保存 | |
| SaveToFile(batfile, cmd); | |
| // 実行 | |
| ProcessExecuteHide(batfile, []); | |
| // 実行結果を読みだす | |
| body := LoadFromFile(resfile); | |
| Result := ParseChatGPTResponse(body); | |
| except | |
| Result := '[ERROR]'; | |
| end; | |
| // 作成したファイルを削除する | |
| DeleteFile(batfile); | |
| Deletefile(jsonfile); | |
| DeleteFile(resfile); | |
| end; | |
| // ChatGPTの応答を解析して文字列で返す | |
| function ParseChatGPTResponse(const json: string): string; | |
| var | |
| JSONData: TJSONData; | |
| JSONObject, MessageObject: TJSONObject; | |
| ChoicesArray: TJSONArray; | |
| begin | |
| Result := ''; // 初期値を空文字に設定 | |
| try | |
| // JSON文字列を解析 | |
| JSONData := GetJSON(json); | |
| // JSONDataがオブジェクトであることを確認 | |
| if not (JSONData is TJSONObject) then | |
| raise Exception.Create('Invalid JSON format'); | |
| JSONObject := TJSONObject(JSONData); | |
| // "choices" 配列を取得 | |
| if not (JSONObject.Find('choices') is TJSONArray) then | |
| raise Exception.Create('"choices" is not a JSON array'); | |
| ChoicesArray := TJSONArray(JSONObject.Find('choices')); | |
| // 最初の配列要素を確認 | |
| if not (ChoicesArray.Items[0] is TJSONObject) then | |
| raise Exception.Create('First item in "choices" is not a JSON object'); | |
| // "message" オブジェクトを取得 | |
| MessageObject := TJSONObject(TJSONObject(ChoicesArray.Items[0]).Find('message')); | |
| // "content" を取得 | |
| if not (MessageObject.Find('content') is TJSONString) then | |
| raise Exception.Create('"content" is not a JSON string'); | |
| Result := MessageObject.Find('content').AsString; // "content" の値を取得 | |
| except | |
| on E: Exception do | |
| begin | |
| Writeln('エラー: ', E.Message); | |
| Result := ''; // エラーが発生した場合は空文字を返す | |
| end; | |
| end; | |
| end; | |
| // バッチファイルを静かに実行する | |
| function ProcessExecuteHide(const AExecutable: string; const AParameters: array of string): Integer; | |
| var | |
| AProcess: TProcess; | |
| I: Integer; | |
| begin | |
| AProcess := TProcess.Create(nil); | |
| try | |
| AProcess.Executable := AExecutable; | |
| for I := Low(AParameters) to High(AParameters) do | |
| AProcess.Parameters.Add(AParameters[I]); | |
| AProcess.Options := [poWaitOnExit]; | |
| AProcess.ShowWindow := swoHIDE; | |
| AProcess.Execute; | |
| Result := AProcess.ExitStatus; | |
| finally | |
| AProcess.Free; | |
| end; | |
| end; | |
| end. |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
プロジェクト全体は、以下よりダウンロードできます。
https://kujirahand.com/blog/go.php?822