Created
January 2, 2024 01:55
-
-
Save twobob/74dc94c03a62da0a2ced3a5203fe7ae1 to your computer and use it in GitHub Desktop.
OPEN AI Unit. in Pascal. Also works for other compatible stuff like LMstudio, Firemonkey cross platfrom test app attached
This file contains 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 OpenAI; | |
interface | |
uses | |
System.SysUtils, | |
System.Classes, | |
System.Generics.Collections, | |
System.Net.HttpClient, | |
System.Net.HttpClientComponent, | |
System.Net.URLClient, | |
Windows, | |
System.JSON; | |
type | |
TOpenAI = class | |
private | |
FBaseURL: string; | |
FAPIKey: string; | |
FHttpClient: TNetHTTPClient; | |
function ConstructJSONBody(AModel: string; AMessages: TArray<TPair<string, string>>; ATemperature: Double): TStringStream; | |
public | |
constructor Create(ABaseURL, AAPIKey: string); | |
destructor Destroy; override; | |
function ChatCompletionsCreate(AModel: string; AMessages: TArray<TPair<string, string>>; ATemperature: Double): string; | |
end; | |
implementation | |
{ TOpenAI } | |
constructor TOpenAI.Create(ABaseURL, AAPIKey: string); | |
begin | |
FBaseURL := ABaseURL; | |
FAPIKey := AAPIKey; | |
FHttpClient := TNetHTTPClient.Create(nil); | |
end; | |
destructor TOpenAI.Destroy; | |
begin | |
FHttpClient.Free; | |
inherited; | |
end; | |
function TOpenAI.ConstructJSONBody(AModel: string; AMessages: TArray<TPair<string, string>>; ATemperature: Double): TStringStream; | |
var | |
JSONMessages: TJSONArray; | |
I: Integer; | |
JSONObj: TJSONObject; | |
begin | |
JSONMessages := TJSONArray.Create; | |
try | |
for I := Low(AMessages) to High(AMessages) do | |
begin | |
JSONObj := TJSONObject.Create; | |
JSONObj.AddPair('role', AMessages[I].Key); | |
JSONObj.AddPair('content', AMessages[I].Value); | |
JSONMessages.AddElement(JSONObj); | |
end; | |
Result := TStringStream.Create( | |
TJSONObject.Create | |
.AddPair('model', AModel) | |
.AddPair('messages', JSONMessages) | |
.AddPair('temperature', TJSONNumber.Create(ATemperature)) | |
.AddPair('max_tokens', TJSONNumber.Create(4096)) | |
.AddPair('stream', TJSONFalse.Create) | |
.ToString); | |
except | |
JSONMessages.Free; | |
raise; | |
end; | |
end; | |
function TOpenAI.ChatCompletionsCreate(AModel: string; AMessages: TArray<TPair<string, string>>; ATemperature: Double): string; | |
var | |
I: Integer; | |
Key, Value, ResultString: string; | |
RequestBody: TStringStream; | |
Response: IHTTPResponse; | |
JSONValue, ChoiceObject: TJSONValue; | |
ChoicesArray: TJSONArray; | |
ContentObject : TJSONValue; | |
FullResponseContent, ContentString: string; | |
begin | |
RequestBody := ConstructJSONBody(AModel, AMessages, ATemperature); | |
try | |
FHttpClient.ResponseTimeout := 240000; // Timeout set to 60000 milliseconds (4 minute) | |
FHttpClient.ContentType := 'application/json'; | |
FHttpClient.CustomHeaders['Authorization'] := 'Bearer ' + FAPIKey; | |
Response := FHttpClient.Post(FBaseURL + '/chat/completions', RequestBody); | |
FullResponseContent := Response.ContentAsString; | |
ContentString := FullResponseContent ; | |
JSONValue := TJSONObject.ParseJSONValue(FullResponseContent); | |
if JSONValue <> nil then | |
try | |
ChoicesArray := (JSONValue as TJSONObject).GetValue('choices') as TJSONArray; | |
if ChoicesArray <> nil then | |
begin | |
ChoiceObject := ChoicesArray.Items[0] as TJSONObject; | |
if ChoiceObject <> nil then | |
begin | |
if ChoiceObject is TJSONObject then | |
begin | |
ResultString := ''; | |
for I := 0 to (ChoiceObject as TJSONObject).Count - 1 do | |
begin | |
Key := (ChoiceObject as TJSONObject).Pairs[I].JsonString.Value; | |
Value := (ChoiceObject as TJSONObject).Pairs[I].JsonValue.Value; | |
ResultString := ResultString + Key + ': ' + Value + '; '; // Concatenate key-value pair with a separator | |
end; | |
if ResultString <> '' then | |
SetLength(ResultString, Length(ResultString) - 2); | |
end; | |
ContentObject := (ChoiceObject as TJSONObject).GetValue('message') as TJSONObject; | |
if ContentObject <> nil then | |
begin | |
if ContentObject is TJSONObject then | |
begin | |
ContentString := (ContentObject as TJSONObject).GetValue('content').Value ; | |
end; | |
end; | |
Result := ContentString; | |
end; | |
end; | |
finally | |
JSONValue.Free; | |
end; | |
finally | |
RequestBody.Free; | |
end; | |
end; | |
end. |
This file contains 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
object Form1: TForm1 | |
Left = 0 | |
Top = 0 | |
Caption = 'Form1' | |
ClientHeight = 632 | |
ClientWidth = 952 | |
FormFactor.Width = 320 | |
FormFactor.Height = 480 | |
FormFactor.Devices = [Desktop] | |
DesignerMasterStyle = 0 | |
object GridPanelLayout1: TGridPanelLayout | |
Anchors = [akLeft, akTop, akRight, akBottom] | |
Size.Width = 952.000000000000000000 | |
Size.Height = 632.000000000000000000 | |
Size.PlatformDefault = False | |
TabOrder = 0 | |
ColumnCollection = < | |
item | |
Value = 100.000000000000000000 | |
end> | |
ControlCollection = < | |
item | |
Column = 0 | |
Control = Panel1 | |
Row = 0 | |
end | |
item | |
Column = 0 | |
Control = Panel2 | |
Row = 1 | |
end> | |
RowCollection = < | |
item | |
Value = 50.000000000000000000 | |
end | |
item | |
Value = 50.000000000000000000 | |
end> | |
object Panel1: TPanel | |
Align = Center | |
Size.Width = 952.000000000000000000 | |
Size.Height = 318.000000000000000000 | |
Size.PlatformDefault = False | |
TabOrder = 0 | |
object tInput: TText | |
Align = Fit | |
Enabled = False | |
Size.Width = 952.000000000000000000 | |
Size.Height = 318.000000000000000000 | |
Size.PlatformDefault = False | |
Text = 'INPUT AREA' | |
Visible = False | |
end | |
object mInput: TMemo | |
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap] | |
DataDetectorTypes = [] | |
Align = Center | |
Size.Width = 952.000000000000000000 | |
Size.Height = 317.000000000000000000 | |
Size.PlatformDefault = False | |
TabOrder = 2 | |
OnKeyDown = mInputKeyDown | |
Viewport.Width = 948.000000000000000000 | |
Viewport.Height = 313.000000000000000000 | |
end | |
end | |
object Panel2: TPanel | |
Align = Center | |
Size.Width = 952.000000000000000000 | |
Size.Height = 317.000000000000000000 | |
Size.PlatformDefault = False | |
TabOrder = 1 | |
object tOutput: TText | |
Position.Y = 8.000000000000000000 | |
Size.Width = 961.000000000000000000 | |
Size.Height = 313.000000000000000000 | |
Size.PlatformDefault = False | |
Text = 'OUTPUT AREA' | |
end | |
end | |
end | |
end |
This file contains 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 Unit1; | |
interface | |
uses | |
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, | |
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects, | |
FMX.Controls.Presentation, FMX.StdCtrls, FMX.Layouts, FMX.Memo.Types, | |
FMX.ScrollBox, FMX.Memo, System.Generics.Collections, Windows, OpenAI; | |
type | |
TForm1 = class(TForm) | |
GridPanelLayout1: TGridPanelLayout; | |
Panel1: TPanel; | |
tInput: TText; | |
Panel2: TPanel; | |
tOutput: TText; | |
mInput: TMemo; | |
procedure mInputKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; | |
Shift: TShiftState); | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
end; | |
var | |
Form1: TForm1; | |
implementation | |
{$R *.fmx} | |
procedure TForm1.mInputKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; | |
Shift: TShiftState); | |
begin | |
// Check if the Enter key was pressed | |
if Key = VK_RETURN then | |
begin | |
// Prevent the beep sound when pressing Enter | |
Key := 0; | |
// Execute the task asynchronously in an anonymous thread | |
TThread.CreateAnonymousThread( | |
procedure | |
var | |
OpenAI: TOpenAI; | |
Response: string; | |
Messages: TArray<TPair<string, string>>; | |
begin | |
// Initialize the OpenAI instance | |
//OpenAI := TOpenAI.Create('http://localhost:1234/v1', 'not-needed'); | |
OpenAI := TOpenAI.Create('https://api.openai.com/v1', 'sk-aWojEH7PSXuM'); | |
try | |
// Prepare your messages array | |
SetLength(Messages, 1); | |
Messages[0] := TPair<string, string>.Create('user', mInput.Text); | |
// Call the ChatCompletionsCreate method asynchronously | |
Response := OpenAI.ChatCompletionsCreate('gpt-3.5-turbo-16k', Messages, 0.7); | |
// Perform the UI update in the main thread | |
TThread.Synchronize(nil, | |
procedure | |
begin | |
tOutput.Text := Response; | |
end); | |
finally | |
OpenAI.Free; | |
end; | |
end | |
).Start; | |
end; | |
end; | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
OPEN AI
LM STUDIO