diff --git a/Blockly/blockly_human_test.html b/Blockly/blockly_human_test.html new file mode 100644 index 0000000..abb91e7 --- /dev/null +++ b/Blockly/blockly_human_test.html @@ -0,0 +1,108 @@ + + + + + Blockly zu Umgangssprache - Mit Schleifen & Zählern + + + + +

Mein "Umgangssprache"-Generator

+

Bauen Sie links Ihre Blöcke. Rechts erscheint die textliche Beschreibung.

+ +
+ + +
+ +
+
+
+

Erzeugter Text:

+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/GoogleGeminiAccess/ApiKey.pas b/GoogleGeminiAccess/ApiKey.pas new file mode 100644 index 0000000..699e5ae --- /dev/null +++ b/GoogleGeminiAccess/ApiKey.pas @@ -0,0 +1,9 @@ +unit ApiKey; + +interface + +const Value = 'AIzaSyALccoMxn0_wcHswavhu5rzdglLeH6gVlI'; + +implementation + +end. diff --git a/GoogleGeminiAccess/GeminiAccess.dpr b/GoogleGeminiAccess/GeminiAccess.dpr new file mode 100644 index 0000000..6212a23 --- /dev/null +++ b/GoogleGeminiAccess/GeminiAccess.dpr @@ -0,0 +1,16 @@ +program GeminiAccess; + +uses + FastMM5, + Vcl.Forms, + MainUnit in 'MainUnit.pas' {Form1}, + ApiKey in 'ApiKey.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. diff --git a/GoogleGeminiAccess/GeminiAccess.dproj b/GoogleGeminiAccess/GeminiAccess.dproj new file mode 100644 index 0000000..92536ab --- /dev/null +++ b/GoogleGeminiAccess/GeminiAccess.dproj @@ -0,0 +1,1130 @@ + + + {B5DEDC9F-4F29-41B9-97D4-2AB0ABC43DC1} + 20.3 + VCL + True + Debug + Win64 + GeminiAccess + 3 + Application + GeminiAccess.dpr + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + GeminiAccess + T:\Myc\Src;$(DCC_UnitSearchPath) + 1031 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + + + vclwinx;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;FireDACCommonDriver;IndyProtocols;vclx;Skia.Package.RTL;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;bindcompfmx;inetdb;FireDACSqliteDriver;DbxClientDriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;DBXMySQLDriver;VclSmp;inet;vcltouch;fmxase;dbrtl;Skia.Package.FMX;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;vcldsnap;DBXInterBaseDriver;IndySystem;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;inetstn;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;fmxobj;bindcompvclsmp;FMXTee;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + vclwinx;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;FireDACCommonDriver;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;bindcompfmx;inetdb;FireDACSqliteDriver;DbxClientDriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;DBXMySQLDriver;VclSmp;inet;vcltouch;fmxase;dbrtl;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;vcldsnap;DBXInterBaseDriver;IndySystem;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;inetstn;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;fmxobj;bindcompvclsmp;FMXTee;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + DEBUG;$(DCC_Define) + true + false + true + true + true + true + true + + + false + PerMonitorV2 + + + PerMonitorV2 + true + 1033 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + PerMonitorV2 + + + PerMonitorV2 + + + + MainSource + + +
Form1
+
+ + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + Application + + + + GeminiAccess.dpr + + + + + + GeminiAccess.exe + true + + + + + GeminiAccess.rsm + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).launchscreen + 64 + + + ..\$(PROJECTNAME).launchscreen + 64 + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + True + True + + + 12 + + + + +
diff --git a/GoogleGeminiAccess/GeminiAccess.res b/GoogleGeminiAccess/GeminiAccess.res new file mode 100644 index 0000000..ca976d8 Binary files /dev/null and b/GoogleGeminiAccess/GeminiAccess.res differ diff --git a/GoogleGeminiAccess/MainUnit.dfm b/GoogleGeminiAccess/MainUnit.dfm new file mode 100644 index 0000000..1c10b26 --- /dev/null +++ b/GoogleGeminiAccess/MainUnit.dfm @@ -0,0 +1,52 @@ +object Form1: TForm1 + Left = 0 + Top = 0 + Caption = 'Form1' + ClientHeight = 1011 + ClientWidth = 1105 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Segoe UI' + Font.Style = [] + OnCreate = FormCreate + OnDestroy = FormDestroy + DesignSize = ( + 1105 + 1011) + TextHeight = 15 + object AnswerMemo: TMemo + Left = 0 + Top = 0 + Width = 1105 + Height = 809 + Anchors = [akLeft, akTop, akRight, akBottom] + ScrollBars = ssVertical + TabOrder = 0 + end + object ExecButton: TButton + Left = 992 + Top = 928 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'Execute' + TabOrder = 1 + OnClick = ExecButtonClick + end + object PromptMemo: TMemo + Left = 0 + Top = 815 + Width = 1105 + Height = 89 + Anchors = [akLeft, akRight, akBottom] + ScrollBars = ssVertical + TabOrder = 2 + end + object ApplicationEvents: TApplicationEvents + OnIdle = ApplicationEventsIdle + Left = 136 + Top = 104 + end +end diff --git a/GoogleGeminiAccess/MainUnit.pas b/GoogleGeminiAccess/MainUnit.pas new file mode 100644 index 0000000..654426c --- /dev/null +++ b/GoogleGeminiAccess/MainUnit.pas @@ -0,0 +1,204 @@ +unit MainUnit; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, + System.Net.HttpClient, System.Net.HttpClientComponent, System.JSON, System.Net.Mime, Vcl.AppEvnts, + Myc.Futures, System.Generics.Collections, ApiKey; + +type + // NEU: Ein Record, um einen einzelnen Redebeitrag in der Konversation zu speichern + TChatTurn = record + Role: string; // 'user' oder 'model' + Text: string; + end; + + TForm1 = class(TForm) + AnswerMemo: TMemo; + ExecButton: TButton; + ApplicationEvents: TApplicationEvents; + PromptMemo: TMemo; + procedure ExecButtonClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure ApplicationEventsIdle(Sender: TObject; var Done: Boolean); + private + FHttpClient: TNetHTTPClient; + FMyApiKey: string; + FAnswer: TFuture; + FChatHistory: TList; // NEU: Liste für den Konversationsverlauf + procedure SendPrompt; + public + { Public declarations } + end; + +var + Form1: TForm1; + +implementation + +{$R *.dfm} + +const + GEMINI_MODEL = 'gemini-2.5-flash-preview-05-20'; + API_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/models/'; + +{ TForm1 } + +procedure TForm1.FormCreate(Sender: TObject); +begin + FHttpClient := TNetHTTPClient.Create(nil); + FMyApiKey := ApiKey.Value; // Eingelesen aus ApiKey.pas + + // NEU: Initialisiert die Liste für den Konversationsverlauf + FChatHistory := TList.Create; + + // Optional: Füge hier einen initialen System-Prompt hinzu, wenn gewünscht. + // Dieser wird dann immer als erste Nachricht mitgesendet. + // var initialTurn: TChatTurn; + // initialTurn.Role := 'user'; + // initialTurn.Text := 'Du bist ein Delphi-Entwicklungs-Assistent...'; + // FChatHistory.Add(initialTurn); +end; + +procedure TForm1.FormDestroy(Sender: TObject); +begin + FAnswer.WaitFor; + FHttpClient.Free; + FChatHistory.Free; // NEU: Gibt die Verlaufsliste frei +end; + +procedure TForm1.ApplicationEventsIdle(Sender: TObject; var Done: Boolean); +var + answerText: string; + modelTurn: TChatTurn; +begin + if FAnswer.Done.IsSet and not ExecButton.Enabled then + begin + answerText := FAnswer.Value; + AnswerMemo.Lines.Add(answerText); + + // NEU: Füge die Antwort des Modells zum Verlauf hinzu + if not answerText.StartsWith('Fehler!') then + begin + modelTurn.Role := 'model'; + modelTurn.Text := answerText; + FChatHistory.Add(modelTurn); + end; + + FAnswer := FAnswer.Null; + ExecButton.Enabled := True; + end; +end; + +procedure TForm1.ExecButtonClick(Sender: TObject); +begin + SendPrompt; +end; + +procedure TForm1.SendPrompt; +var + userPrompt: string; + userTurn: TChatTurn; +begin + if not ExecButton.Enabled then + Exit; + + userPrompt := PromptMemo.Lines.Text; + if userPrompt.IsEmpty then + begin + ShowMessage('Bitte geben Sie einen Prompt ein.'); + Exit; + end; + + // NEU: Füge die aktuelle Benutzereingabe zum Verlauf hinzu + userTurn.Role := 'user'; + userTurn.Text := userPrompt; + FChatHistory.Add(userTurn); + + // NEU: Leere das Eingabefeld für die nächste Nachricht + PromptMemo.Clear; + + ExecButton.Enabled := False; + AnswerMemo.Lines.Add(''); + AnswerMemo.Lines.Add('--- [USER] ---'); + AnswerMemo.Lines.Add(userPrompt); + AnswerMemo.Lines.Add('... sende Anfrage an Gemini ...'); + + FAnswer := TFuture.Construct( + function: string + var + jsonRequest: TJSONObject; + jsonContents: TJSONArray; + requestBody: TStringStream; + response: IHTTPResponse; + responseJson: TJSONValue; + apiUrl: string; + turn: TChatTurn; + begin + try + // 1. JSON-Body aus dem gesamten Konversationsverlauf erstellen + jsonRequest := TJSONObject.Create; + try + jsonContents := TJSONArray.Create; + jsonRequest.AddPair('contents', jsonContents); + + // NEU: Iteriere durch den Verlauf und baue die JSON-Struktur auf + for turn in FChatHistory do + begin + var jsonTurn := TJSONObject.Create; + jsonTurn.AddPair('role', TJSONString.Create(turn.Role)); + + var jsonParts := TJSONArray.Create; + jsonTurn.AddPair('parts', jsonParts); + + var jsonText := TJSONObject.Create; + jsonText.AddPair('text', TJSONString.Create(turn.Text)); + jsonParts.Add(jsonText); + + jsonContents.Add(jsonTurn); + end; + + // 2. Request senden + requestBody := TStringStream.Create(jsonRequest.ToString, TEncoding.UTF8); + try + apiUrl := API_BASE_URL + GEMINI_MODEL + ':generateContent?key=' + FMyApiKey; + response := FHttpClient.Post(apiUrl, requestBody, nil); + + // 3. Antwort verarbeiten + if (response.StatusCode = 200) then + begin + responseJson := TJSONObject.ParseJSONValue(response.ContentAsString(TEncoding.UTF8)); + try + Result := responseJson.GetValue('candidates') + .Items[0].GetValue('content') + .GetValue('parts') + .Items[0].GetValue('text'); + finally + responseJson.Free; + end; + end + else + begin + Result := 'Fehler! Status: ' + response.StatusCode.ToString + ' - ' + response.StatusText + + sLineBreak + response.ContentAsString; + end; + finally + requestBody.Free; + end; + finally + jsonRequest.Free; + end; + except + on E: Exception do + begin + Result := '--- FEHLER IM TASK ---' + sLineBreak + E.Message; + end; + end; + end); +end; + +end. + diff --git a/Src/Myc.Trade.DataStream.pas b/Src/Myc.Trade.DataStream.pas index ba582f2..3959b46 100644 --- a/Src/Myc.Trade.DataStream.pas +++ b/Src/Myc.Trade.DataStream.pas @@ -5,7 +5,7 @@ unit Myc.Trade.DataStream; Provides a data server for loading time-series data and streaming it. This unit contains the core components for handling historical data: - - TDataRecord: A generic record for a single time-stamped data entry. + - TAuraFileDataRecord: A generic record for a single time-stamped data entry. - IDataServer/TAuraDataServer: A server component responsible for loading and caching series of data files from disk. Each server instance manages its own cache, but all instances share a central load gate. @@ -29,11 +29,6 @@ uses Myc.Trade.DataPoint; type - // A generic record for a single time-stamped data entry. - TDataRecord = packed record - TimeStamp: TDateTime; - Data: T; - end; // Represents a generic data stream capable of providing sequential data chunks. IDataStream = interface @@ -69,10 +64,16 @@ type procedure ClearCache; end; + // A generic record for a single time-stamped data entry. + TAuraFileDataRecord = packed record + TimeStamp: TDateTime; + Data: T; + end; + IAuraDataServer = interface(IDataServer) ['{481E27DE-DC58-49AF-B8A8-B6316980C423}'] - function LoadDataFile(const FileName: string): TFuture>>; - function LoadDataSeries(const FileName: string): TFuture>>; + function LoadDataFile(const FileName: string): TFuture>>; + function LoadDataSeries(const FileName: string): TFuture>>; function EnumerateAssetFiles: TArray; end; @@ -87,7 +88,7 @@ type Name: String; Age: TDateTime; LastUsed: TDateTime; - Data: TFuture>>; + Data: TFuture>>; end; private // The cache is per-instance. @@ -101,8 +102,8 @@ type FLoadGate: TLatch; protected - class function ReadCompressedData(const InputStream: TStream): TArray>; static; - class function ReadUncompressedData(const InputStream: TStream): TArray>; static; + class function ReadCompressedData(const InputStream: TStream): TArray>; static; + class function ReadUncompressedData(const InputStream: TStream): TArray>; static; public constructor Create(const APath: String); @@ -123,8 +124,8 @@ type procedure ClearCache; function EnumerateAssetFiles: TArray; - function LoadDataFile(const FileName: string): TFuture>>; - function LoadDataSeries(const FileName: string): TFuture>>; + function LoadDataFile(const FileName: string): TFuture>>; + function LoadDataSeries(const FileName: string): TFuture>>; property Path: String read GetPath; end; @@ -135,9 +136,9 @@ type FDataServer: TAuraDataServer; FIsLiveData: TMutable.IWriteable; FCurrentFileName: string; - FCurrentData: TFuture>>; + FCurrentData: TFuture>>; FNextFileName: string; - FNextData: TFuture>>; + FNextData: TFuture>>; FCurrPosInFile: Int64; FCurrentIdx: Int64; FLastTimeStamp: TDateTime; @@ -314,12 +315,12 @@ begin Result := FPath; end; -function TAuraDataServer.LoadDataFile(const FileName: string): TFuture>>; +function TAuraDataServer.LoadDataFile(const FileName: string): TFuture>>; var parsedPath, parsedSymbol: string; parsedYear, parsedMonth: Integer; begin - Result := TFuture>>.Null; + Result := TFuture>>.Null; if not TryParseFileName(FileName, parsedPath, parsedSymbol, parsedYear, parsedMonth) then exit; @@ -368,8 +369,8 @@ begin .Construct( TLatch.Enqueue(FLoadGate), // Use shared class var FLoadGate function: TBytes begin Result := TFile.ReadAllBytes(capFileName); end) - .Chain>>( - function(bytes: TBytes): TArray> + .Chain>>( + function(bytes: TBytes): TArray> begin var zipMemoryStream := TBytesStream.Create(bytes); try @@ -383,9 +384,9 @@ begin else if TFile.Exists(FileName) then begin Result := - TFuture>>.Construct( + TFuture>>.Construct( TLatch.Enqueue(FLoadGate), // Use shared class var FLoadGate - function: TArray> + function: TArray> begin if TFile.Exists(capFileName) then begin @@ -418,11 +419,11 @@ begin end; end; -function TAuraDataServer.LoadDataSeries(const FileName: string): TFuture>>; +function TAuraDataServer.LoadDataSeries(const FileName: string): TFuture>>; var loadedState: TState; - loadedFiles: TArray>>>; - liveData: TFuture>>; + loadedFiles: TArray>>>; + liveData: TFuture>>; tabFiles: TList; currentFile: string; liveFilePath: string; @@ -452,7 +453,7 @@ begin end; end; - var loadedFileList := TList>>>.Create; + var loadedFileList := TList>>>.Create; var loadStates := TList.Create; try for currentFile in tabFiles do @@ -462,7 +463,7 @@ begin loadStates.Add(data.Done); end; - liveData := TFuture>>.Null; + liveData := TFuture>>.Null; if liveFilePath <> '' then begin liveData := LoadDataFile(liveFilePath); @@ -481,11 +482,11 @@ begin end; Result := - TFuture>>.Construct( + TFuture>>.Construct( loadedState, - function: TArray> + function: TArray> begin - var tickList := TList>.Create; + var tickList := TList>.Create; try var overallLastTabTickTime: TDateTime := 0; var cnt := 0; @@ -508,7 +509,7 @@ begin ); end; -class function TAuraDataServer.ReadCompressedData(const InputStream: TStream): TArray>; +class function TAuraDataServer.ReadCompressedData(const InputStream: TStream): TArray>; var decompressionStream: TStream; localHeader: TZipHeader; @@ -547,7 +548,7 @@ begin end; end; -class function TAuraDataServer.ReadUncompressedData(const InputStream: TStream): TArray>; +class function TAuraDataServer.ReadUncompressedData(const InputStream: TStream): TArray>; var fileSize: Int64; recordCount, bytesRead: Integer; @@ -555,10 +556,10 @@ begin SetLength(Result, 0); InputStream.Position := 0; fileSize := InputStream.Size; - if (fileSize = 0) or ((fileSize mod SizeOf(TDataRecord)) <> 0) then + if (fileSize = 0) or ((fileSize mod SizeOf(TAuraFileDataRecord)) <> 0) then exit; - recordCount := fileSize div SizeOf(TDataRecord); + recordCount := fileSize div SizeOf(TAuraFileDataRecord); if recordCount > 0 then begin SetLength(Result, recordCount); @@ -596,8 +597,8 @@ end; function TAuraFileStream.GetChunk(var Data: array of TDataPoint): Integer; var - item: TDataRecord; - currData: TArray>; + item: TAuraFileDataRecord; + currData: TArray>; begin Result := 0; if not FCurrentData.Done.IsSet then