ttw_fmx_v10/Services/uKandinskyAPI.pas

226 lines
6.5 KiB
Plaintext
Raw Blame History

unit uKandinskyAPI;
interface
uses
System.SysUtils, System.Classes, System.JSON, System.Net.HttpClient,
System.Net.URLClient, System.NetConsts, system.StrUtils, System.Net.Mime,
System.NetEncoding, System.Threading;
type
TGenerationDoneEvent = procedure(Sender: TObject; const FileName: string) of object;
TStatusUpdateEvent = procedure(Sender: TObject; const Message: string) of object;
TErrorEvent = procedure(Sender: TObject; const ErrorMessage: string) of object;
TFusionBrainAPI = class(TComponent)
private
FBaseURL: string;
FApiKey: string;
FSecretKey: string;
FClient: THTTPClient;
FOnGenerationDone: TGenerationDoneEvent;
FOnStatusUpdate: TStatusUpdateEvent;
FOnError: TErrorEvent;
procedure DoStatusUpdate(const AMessage: string);
procedure DoGenerationDone(const AFileName: string);
procedure DoError(const AErrorMessage: string);
function GetAuthHeaders: TNetHeaders;
function GetPipeline: string;
function Generate(const Prompt, PipelineId: string): string;
function CheckGeneration(const RequestId: string): TArray<string>;
procedure SaveBase64Image(const Base64Str, FileName: string);
public
constructor Create(AOwner: TComponent; aKey:string; aSecret:string);
destructor Destroy; override;
procedure StartGeneration(const APrompt: string);
property OnGenerationDone: TGenerationDoneEvent read FOnGenerationDone write FOnGenerationDone;
property OnStatusUpdate: TStatusUpdateEvent read FOnStatusUpdate write FOnStatusUpdate;
property OnError: TErrorEvent read FOnError write FOnError;
end;
implementation
uses ugeneral;
constructor TFusionBrainAPI.Create(AOwner: TComponent; aKey:string; aSecret:string);
begin
inherited Create(AOwner);
FClient := THTTPClient.Create;
FBaseURL := 'https://api-key.fusionbrain.ai/';
FApiKey :=aKey;
FSecretKey := aSecret;
end;
destructor TFusionBrainAPI.Destroy;
begin
FClient.Free;
inherited;
end;
procedure TFusionBrainAPI.StartGeneration(const APrompt: string);
var
Task: ITask;
begin
Task :=TTask.Run(procedure
var
PipelineID, UUID, FileName: string;
Links: TArray<string>;
begin
try
TThread.Queue(nil, procedure begin DoStatusUpdate('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...'); end);
PipelineID := GetPipeline;
TThread.Queue(nil, procedure begin DoStatusUpdate('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...'); end);
UUID := Generate(APrompt, PipelineID);
TThread.Queue(nil, procedure begin DoStatusUpdate('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...'); end);
Links := CheckGeneration(UUID);
FileName := myConst.AppDataPath + 'imgs\kandinsky_' + FormatDateTime('yyyymmddhhnnss', Now) + '.jpg';
SaveBase64Image(Links[0], FileName);
TThread.Queue(nil, procedure begin DoGenerationDone(FileName); end);
except
on E: Exception do
TThread.Queue(nil, procedure begin DoError(E.Message); end);
end;
end);
end;
function TFusionBrainAPI.GetAuthHeaders: TNetHeaders;
begin
SetLength(Result, 2);
Result[0] := TNetHeader.Create('X-Key', 'Key ' + FApiKey);
Result[1] := TNetHeader.Create('X-Secret', 'Secret ' + FSecretKey);
end;
function TFusionBrainAPI.GetPipeline: string;
var
Response: IHTTPResponse;
Json: TJSONArray;
begin
Response := FClient.Get(FBaseURL + 'key/api/v1/pipelines', nil, GetAuthHeaders);
Json := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONArray;
try
Result := Json.Items[0].GetValue<string>('id');
finally
Json.Free;
end;
end;
function TFusionBrainAPI.Generate(const Prompt, PipelineId: string): string;
var
Params, Root: TJSONObject;
Multipart: TMultipartFormData;
Response: IHTTPResponse;
Json: TJSONObject;
begin
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> JSON
Params := TJSONObject.Create;
Root := TJSONObject.Create;
try
Params.AddPair('query', Prompt);
Root.AddPair('type', 'GENERATE');
Root.AddPair('numImages', TJSONNumber.Create(1));
Root.AddPair('width', TJSONNumber.Create(512));
Root.AddPair('height', TJSONNumber.Create(512));
Root.AddPair('generateParams', Params);
Multipart := TMultipartFormData.Create;
try
Multipart.AddField('pipeline_id', PipelineId);
Multipart.AddField('params', Root.ToString, 'application/json');
Response := FClient.Post(FBaseURL + 'key/api/v1/pipeline/run', Multipart, nil, GetAuthHeaders);
Json := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONObject;
try
Result := Json.GetValue<string>('uuid');
finally
Json.Free;
end;
finally
Multipart.Free;
end;
finally
Root.Free;
// Params <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> Root
end;
end;
function TFusionBrainAPI.CheckGeneration(const RequestId: string): TArray<string>;
const
MaxAttempts = 60;
var
Response: IHTTPResponse;
Json, ResultObj: TJSONObject;
Files: TJSONArray;
i, Attempt: Integer;
Status: string;
begin
Attempt := 0;
while Attempt < MaxAttempts do
begin
Sleep(5000);
Inc(Attempt);
Response := FClient.Get(FBaseURL + 'key/api/v1/pipeline/status/' + RequestId, nil, GetAuthHeaders);
Json := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONObject;
try
Status := Json.GetValue<string>('status');
if Status = 'DONE' then
begin
ResultObj := Json.GetValue<TJSONObject>('result');
Files := ResultObj.GetValue<TJSONArray>('files');
SetLength(Result, Files.Count);
for i := 0 to Files.Count - 1 do
Result[i] := Files.Items[i].Value;
Exit;
end
else if Status = 'FAILED' then
raise Exception.Create('Generation failed');
finally
Json.Free;
end;
end;
raise Exception.Create('Timeout waiting for generation');
end;
procedure TFusionBrainAPI.SaveBase64Image(const Base64Str, FileName: string);
var
DecodedStream: TMemoryStream;
InputStr: TStringStream;
begin
DecodedStream := TMemoryStream.Create;
InputStr := TStringStream.Create(Base64Str, TEncoding.ASCII);
try
TNetEncoding.Base64.Decode(InputStr, DecodedStream);
DecodedStream.SaveToFile(FileName);
finally
DecodedStream.Free;
InputStr.Free;
end;
end;
procedure TFusionBrainAPI.DoStatusUpdate(const AMessage: string);
begin
if Assigned(FOnStatusUpdate) then
FOnStatusUpdate(Self, AMessage);
end;
procedure TFusionBrainAPI.DoGenerationDone(const AFileName: string);
begin
if Assigned(FOnGenerationDone) then
FOnGenerationDone(Self, AFileName);
end;
procedure TFusionBrainAPI.DoError(const AErrorMessage: string);
begin
if Assigned(FOnError) then
FOnError(Self, AErrorMessage);
end;
end.