Gemini Test
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
unit MainUnit;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Types,
|
||||
System.UITypes,
|
||||
System.Classes,
|
||||
System.Variants,
|
||||
FMX.Types,
|
||||
FMX.Controls,
|
||||
FMX.Forms,
|
||||
FMX.Graphics,
|
||||
FMX.Dialogs,
|
||||
FMX.Memo.Types,
|
||||
FMX.ScrollBox,
|
||||
FMX.Memo,
|
||||
FMX.Controls.Presentation,
|
||||
FMX.StdCtrls,
|
||||
FMX.Edit,
|
||||
FMX.ListBox,
|
||||
Myc.Api.Gemini,
|
||||
FMX.TabControl;
|
||||
|
||||
type
|
||||
TForm1 = class(TForm)
|
||||
AskButton: TButton;
|
||||
Edit1: TEdit;
|
||||
ModelsComboBox: TComboBox;
|
||||
QuotaLabel: TLabel;
|
||||
AskMemo: TMemo;
|
||||
ResetChatButton: TButton;
|
||||
TabControl1: TTabControl;
|
||||
ChatTabItem: TTabItem;
|
||||
CacheTabItem: TTabItem;
|
||||
SysInstrTabItem: TTabItem;
|
||||
ChatMemo: TMemo;
|
||||
CacheMemo: TMemo;
|
||||
SystemInstructionMemo: TMemo;
|
||||
UploadCacheButton: TButton;
|
||||
ThinkingCheckBox: TCheckBox;
|
||||
GlobalQuoteLabel: TLabel;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure AskButtonClick(Sender: TObject);
|
||||
procedure Edit1Exit(Sender: TObject);
|
||||
procedure ResetChatButtonClick(Sender: TObject);
|
||||
procedure UploadCacheButtonClick(Sender: TObject);
|
||||
private
|
||||
FChat: IGeminiChat;
|
||||
// Holds the client configured with the active cache
|
||||
FCachedClient: IGeminiClient;
|
||||
procedure InitChat;
|
||||
procedure UpdateQuotaDisplay;
|
||||
public
|
||||
procedure GetAvailableModels;
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Threading,
|
||||
Myc.System.Quota; // Einbindung für den globalen Zähler
|
||||
|
||||
{$R *.fmx}
|
||||
|
||||
const
|
||||
FallbackModel = 'gemini-3-flash-preview';
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
begin
|
||||
// Load default instructions if file exists
|
||||
if FileExists('T:\Myc\KI\gemini.md') then
|
||||
SystemInstructionMemo.Lines.LoadFromFile('T:\Myc\KI\gemini.md', TEncoding.UTF8);
|
||||
|
||||
// Initialen Global-Stand anzeigen
|
||||
UpdateQuotaDisplay;
|
||||
|
||||
GetAvailableModels;
|
||||
InitChat;
|
||||
end;
|
||||
|
||||
procedure TForm1.InitChat;
|
||||
begin
|
||||
if Assigned(FCachedClient) then
|
||||
begin
|
||||
FChat := FCachedClient.StartChat;
|
||||
ChatMemo.Lines.Add('--- New Chat Session (Cached Content Active) ---');
|
||||
end
|
||||
else
|
||||
begin
|
||||
FChat := nil; // Lazy init in AskButton
|
||||
ChatMemo.Lines.Add('--- New Chat Session ---');
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.ResetChatButtonClick(Sender: TObject);
|
||||
begin
|
||||
InitChat;
|
||||
end;
|
||||
|
||||
procedure TForm1.UpdateQuotaDisplay;
|
||||
begin
|
||||
GlobalQuoteLabel.Text := 'Total: ' + TGlobalQuota.GetTotal.ToString + ', Today: ' + TGlobalQuota.GetDailyTotal.ToString;
|
||||
end;
|
||||
|
||||
procedure TForm1.AskButtonClick(Sender: TObject);
|
||||
var
|
||||
apiKey: string;
|
||||
modelName: string;
|
||||
prompt: string;
|
||||
begin
|
||||
apiKey := Edit1.Text;
|
||||
prompt := AskMemo.Text;
|
||||
|
||||
if ModelsComboBox.ItemIndex > -1 then
|
||||
modelName := ModelsComboBox.Items[ModelsComboBox.ItemIndex]
|
||||
else
|
||||
modelName := FallbackModel;
|
||||
|
||||
// --- LAZY INIT ---
|
||||
if FChat = nil then
|
||||
begin
|
||||
var client: IGeminiClient := TGeminiClient.Create(apiKey, modelName);
|
||||
|
||||
// 1. System Instructions (Ohne Hack, purer Text)
|
||||
if not SystemInstructionMemo.Text.Trim.IsEmpty then
|
||||
client.SystemInstruction := SystemInstructionMemo.Text;
|
||||
|
||||
// 2. Native Thinking aktivieren
|
||||
// Die API-Unit entscheidet, ob das Modell es unterstützt.
|
||||
// Falls ja, wird der 'thinking' Parameter gesendet.
|
||||
client.EnableThinking := ThinkingCheckBox.IsChecked;
|
||||
|
||||
FChat := client.StartChat;
|
||||
end;
|
||||
|
||||
AskButton.Enabled := False;
|
||||
ChatMemo.Lines.Add(sLineBreak + 'User: "' + prompt + '"');
|
||||
ChatMemo.Lines.Add('Gemini: ');
|
||||
AskMemo.Text := '';
|
||||
|
||||
TTask.Run(
|
||||
procedure
|
||||
var
|
||||
CurrentChat: IGeminiChat;
|
||||
resultData: TGeminiResult;
|
||||
begin
|
||||
CurrentChat := FChat;
|
||||
if CurrentChat = nil then
|
||||
exit;
|
||||
|
||||
// --- STREAMING ---
|
||||
resultData :=
|
||||
CurrentChat.SendMessageStream(
|
||||
prompt,
|
||||
procedure(const TextChunk: string; IsThought: Boolean)
|
||||
begin
|
||||
TThread.Queue(
|
||||
nil,
|
||||
procedure
|
||||
begin
|
||||
if IsThought then
|
||||
begin
|
||||
// Visuelle Kennzeichnung für Gedanken
|
||||
// (Hier einfach in eckigen Klammern, besser wäre Farbe)
|
||||
ChatMemo.Text := ChatMemo.Text + ' [Think: ' + TextChunk + '] ';
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Normale Antwort
|
||||
ChatMemo.Text := ChatMemo.Text + TextChunk;
|
||||
end;
|
||||
|
||||
ChatMemo.GoToTextEnd;
|
||||
end
|
||||
);
|
||||
end
|
||||
);
|
||||
|
||||
// Abschluss im Main Thread
|
||||
TThread.Queue(
|
||||
nil,
|
||||
procedure
|
||||
begin
|
||||
if resultData.Text.StartsWith('Error') then
|
||||
ChatMemo.Lines.Add(resultData.Text);
|
||||
|
||||
// Update Labels (Session & Global Registry)
|
||||
QuotaLabel.Text := Format('Input: %d | Output: %d', [resultData.Usage.PromptTokens, resultData.Usage.CandidatesTokens]);
|
||||
UpdateQuotaDisplay;
|
||||
|
||||
AskButton.Enabled := True;
|
||||
end
|
||||
);
|
||||
end
|
||||
);
|
||||
end;
|
||||
|
||||
procedure TForm1.Edit1Exit(Sender: TObject);
|
||||
begin
|
||||
GetAvailableModels;
|
||||
end;
|
||||
|
||||
procedure TForm1.GetAvailableModels;
|
||||
var
|
||||
apiKey: string;
|
||||
begin
|
||||
apiKey := Edit1.Text.Trim;
|
||||
if apiKey.IsEmpty then
|
||||
exit;
|
||||
|
||||
ChatMemo.Lines.Add('Fetching available models...');
|
||||
|
||||
TTask.Run(
|
||||
procedure
|
||||
var
|
||||
client: IGeminiClient;
|
||||
modelList: TArray<string>;
|
||||
begin
|
||||
client := TGeminiClient.Create(apiKey);
|
||||
modelList := client.ListModels;
|
||||
|
||||
TThread.Queue(
|
||||
nil,
|
||||
procedure
|
||||
var
|
||||
mName: string;
|
||||
begin
|
||||
if Length(modelList) = 0 then
|
||||
begin
|
||||
ChatMemo.Lines.Add('No models found.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
ModelsComboBox.BeginUpdate;
|
||||
try
|
||||
ModelsComboBox.Items.Clear;
|
||||
|
||||
for mName in modelList do
|
||||
ModelsComboBox.Items.Add(mName);
|
||||
|
||||
// Versuche Fallback zu finden (ggf. ohne Emoji suffix match)
|
||||
// Vereinfacht: Wähle ersten Index
|
||||
if ModelsComboBox.Items.Count > 0 then
|
||||
begin
|
||||
ModelsComboBox.ItemIndex := ModelsComboBox.Items.IndexOf(FallbackModel);
|
||||
if ModelsComboBox.ItemIndex < 0 then
|
||||
ModelsComboBox.ItemIndex := 0;
|
||||
end;
|
||||
|
||||
ChatMemo.Lines.Add(Format('Loaded %d models.', [Length(modelList)]));
|
||||
finally
|
||||
ModelsComboBox.EndUpdate;
|
||||
end;
|
||||
end
|
||||
);
|
||||
end
|
||||
);
|
||||
end;
|
||||
|
||||
procedure TForm1.UploadCacheButtonClick(Sender: TObject);
|
||||
var
|
||||
apiKey: string;
|
||||
content: string;
|
||||
sysInstr: string;
|
||||
modelName: string;
|
||||
begin
|
||||
apiKey := Edit1.Text;
|
||||
content := CacheMemo.Text;
|
||||
|
||||
// Keine künstlichen Prompts mehr, nur die reinen Instruktionen
|
||||
sysInstr := SystemInstructionMemo.Text;
|
||||
|
||||
if content.Trim.IsEmpty then
|
||||
begin
|
||||
ChatMemo.Lines.Add('Error: Cache content is empty.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Remove Emoji suffix if present from ComboBox for API call
|
||||
if ModelsComboBox.ItemIndex > -1 then
|
||||
modelName := ModelsComboBox.Items[ModelsComboBox.ItemIndex].Split([' '])[0]
|
||||
else
|
||||
modelName := FallbackModel;
|
||||
|
||||
UploadCacheButton.Enabled := False;
|
||||
ChatMemo.Lines.Add('Creating Cache (this may take a moment)...');
|
||||
|
||||
TTask.Run(
|
||||
procedure
|
||||
var
|
||||
client: IGeminiClient;
|
||||
cacheName: string;
|
||||
errMsg: string;
|
||||
begin
|
||||
try
|
||||
// 1. Client erstellen
|
||||
client := TGeminiClient.Create(apiKey, modelName);
|
||||
|
||||
// 2. Cache erstellen (Content + SysInstr)
|
||||
// Hinweis: Native Thinking ist ein Parameter der GENERIERUNG, nicht des Caches.
|
||||
// Daher laden wir den Cache "neutral" hoch.
|
||||
cacheName := client.CreateCache(content, sysInstr, 300);
|
||||
|
||||
// 3. Cache aktivieren
|
||||
client.ActiveCacheName := cacheName;
|
||||
|
||||
// 4. Client speichern
|
||||
// Wenn der User später "Ask" klickt, wird dort EnableThinking gesetzt
|
||||
FCachedClient := client;
|
||||
|
||||
TThread.Queue(
|
||||
nil,
|
||||
procedure
|
||||
begin
|
||||
ChatMemo.Lines.Add('Success: Cache created!');
|
||||
ChatMemo.Lines.Add('ID: ' + cacheName);
|
||||
|
||||
InitChat;
|
||||
UploadCacheButton.Enabled := True;
|
||||
end
|
||||
);
|
||||
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
errMsg := E.Message;
|
||||
TThread.Queue(
|
||||
nil,
|
||||
procedure
|
||||
begin
|
||||
ChatMemo.Lines.Add('Cache Upload Failed:');
|
||||
ChatMemo.Lines.Add(errMsg);
|
||||
UploadCacheButton.Enabled := True;
|
||||
end
|
||||
);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
);
|
||||
end;
|
||||
|
||||
end.
|
||||
Reference in New Issue
Block a user