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.