Test-Apps für Gemini Api und Blockly
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Blockly zu Umgangssprache - Mit Schleifen & Zählern</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; }
|
||||
#container { display: flex; }
|
||||
#outputArea { margin-left: 20px; }
|
||||
#codeOutput { width: 400px; height: 580px; font-size: 14px; white-space: pre-wrap; border: 1px solid #ccc; }
|
||||
#blocklyDiv { height: 600px; width: 800px; }
|
||||
.button-bar { margin-bottom: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Mein "Umgangssprache"-Generator</h1>
|
||||
<p>Bauen Sie links Ihre Blöcke. Rechts erscheint die textliche Beschreibung.</p>
|
||||
|
||||
<div class="button-bar">
|
||||
<button onclick="saveWorkspace()">Speichern</button>
|
||||
<button onclick="loadWorkspace()">Letzten Stand laden</button>
|
||||
</div>
|
||||
|
||||
<div id="container">
|
||||
<div id="blocklyDiv"></div>
|
||||
<div id="outputArea">
|
||||
<h2>Erzeugter Text:</h2>
|
||||
<textarea id="codeOutput" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/blockly/blockly_compressed.js"></script>
|
||||
<script src="https://unpkg.com/blockly/blocks_compressed.js"></script>
|
||||
<script src="https://unpkg.com/blockly/msg/de.js"></script>
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
|
||||
let workspace;
|
||||
|
||||
// === UNSER UMGANGSSPRACHE-GENERATOR ===
|
||||
Blockly.Human = new Blockly.Generator('Human');
|
||||
Blockly.Human.ORDER_ATOMIC = 0;
|
||||
Blockly.Human.scrub_ = function(block, code, opt_thisOnly) { const nextBlock = block.nextConnection && block.nextConnection.targetBlock(); const nextCode = opt_thisOnly ? '' : Blockly.Human.blockToCode(nextBlock); return code + nextCode; };
|
||||
Blockly.Human.prefixLines = function(text, prefix) { return prefix + text.split(/\n(?!$)/).join('\n' + prefix); };
|
||||
|
||||
// --- Generatoren für die einzelnen Blöcke ---
|
||||
Blockly.Human.forBlock['controls_if'] = function(block) { let conditionCode = Blockly.Human.valueToCode(block, 'IF0', Blockly.Human.ORDER_ATOMIC) || 'eine Bedingung erfüllt ist'; let branchCode = Blockly.Human.statementToCode(block, 'DO0') || 'nichts.\n'; let code = `Also, überprüfe, ${conditionCode}.\n`; code += `Wenn das zutrifft, dann mach Folgendes:\n`; code += Blockly.Human.prefixLines(branchCode, ' '); return code; };
|
||||
Blockly.Human.forBlock['logic_compare'] = function(block) { const OPERATORS = {'EQ': 'ist gleich', 'NEQ': 'ist nicht gleich', 'LT': 'ist kleiner als', 'LTE': 'ist kleiner oder gleich', 'GT': 'ist größer als', 'GTE': 'ist größer oder gleich'}; const operator = OPERATORS[block.getFieldValue('OP')]; const value_a = Blockly.Human.valueToCode(block, 'A', Blockly.Human.ORDER_ATOMIC) || 'irgendetwas'; const value_b = Blockly.Human.valueToCode(block, 'B', Blockly.Human.ORDER_ATOMIC) || 'irgendetwas anderes'; const code = `ob der Wert von ${value_a} ${operator} als ${value_b}`; return [code, Blockly.Human.ORDER_ATOMIC]; };
|
||||
Blockly.Human.forBlock['math_number'] = function(block) { return [String(block.getFieldValue('NUM')), Blockly.Human.ORDER_ATOMIC]; };
|
||||
Blockly.Human.forBlock['variables_get'] = function(block) { const varId = block.getFieldValue('VAR'); const variable = block.workspace.getVariableById(varId); const varName = variable ? variable.name : 'unbekannt'; return [`der Variable "${varName}"`, Blockly.Human.ORDER_ATOMIC]; };
|
||||
Blockly.Human.forBlock['variables_set'] = function(block) { const varId = block.getFieldValue('VAR'); const variable = block.workspace.getVariableById(varId); const varName = variable ? variable.name : 'unbekannt'; const value = Blockly.Human.valueToCode(block, 'VALUE', Blockly.Human.ORDER_ATOMIC) || 'nichts'; return `Setze die Variable "${varName}" auf den Wert ${value}.\n`; };
|
||||
Blockly.Human.forBlock['text_print'] = function(block) { const value = Blockly.Human.valueToCode(block, 'TEXT', Blockly.Human.ORDER_ATOMIC) || '"nichts"'; return `Gib auf dem Bildschirm aus: ${value}\n`; };
|
||||
Blockly.Human.forBlock['text'] = function(block) { return [`"${block.getFieldValue('TEXT')}"`, Blockly.Human.ORDER_ATOMIC]; };
|
||||
Blockly.Human.forBlock['controls_repeat_ext'] = function(block) { const repeats = Blockly.Human.valueToCode(block, 'TIMES', Blockly.Human.ORDER_ATOMIC) || 'einige Male'; const branch = Blockly.Human.statementToCode(block, 'DO') || 'mache nichts.\n'; let code = `Wiederhole die folgenden Schritte ${repeats} Mal:\n`; code += Blockly.Human.prefixLines(branch, ' '); return code; };
|
||||
|
||||
// NEU: Generator für den "ändere Variable um"-Block
|
||||
Blockly.Human.forBlock['math_change'] = function(block) {
|
||||
const varId = block.getFieldValue('VAR');
|
||||
const variable = block.workspace.getVariableById(varId);
|
||||
const varName = variable ? variable.name : 'unbekannt';
|
||||
const delta = Blockly.Human.valueToCode(block, 'DELTA', Blockly.Human.ORDER_ATOMIC) || '0';
|
||||
return `Ändere die Variable "${varName}" um den Wert ${delta}.\n`;
|
||||
};
|
||||
|
||||
|
||||
// === INITIALISIERUNG VON BLOCKLY ===
|
||||
|
||||
const toolboxXml = `
|
||||
<xml>
|
||||
<category name="Logik" colour="%{BKY_LOGIC_HUE}">
|
||||
<block type="controls_if"></block>
|
||||
<block type="logic_compare"></block>
|
||||
</category>
|
||||
<category name="Schleifen" colour="%{BKY_LOOPS_HUE}">
|
||||
<block type="controls_repeat_ext">
|
||||
<value name="TIMES"><shadow type="math_number"><field name="NUM">10</field></shadow></value>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Text" colour="%{BKY_TEXTS_HUE}">
|
||||
<block type="text_print"></block>
|
||||
<block type="text"></block>
|
||||
</category>
|
||||
<category name="Mathematik" colour="%{BKY_MATH_HUE}">
|
||||
<block type="math_number"></block>
|
||||
<block type="math_change">
|
||||
<value name="DELTA"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Variablen" colour="%{BKY_VARIABLES_HUE}" custom="VARIABLE"></category>
|
||||
</xml>`;
|
||||
|
||||
workspace = Blockly.inject('blocklyDiv', {
|
||||
toolbox: toolboxXml
|
||||
});
|
||||
|
||||
// === Funktionen für Speichern und Laden (unverändert) ===
|
||||
window.saveWorkspace = function() { const state = Blockly.serialization.workspaces.save(workspace); localStorage.setItem('blocklyWorkspace', JSON.stringify(state)); alert('Arbeitsbereich gespeichert!'); }
|
||||
window.loadWorkspace = function() { const stateString = localStorage.getItem('blocklyWorkspace'); if (!stateString) { return; } const state = JSON.parse(stateString); Blockly.serialization.workspaces.load(state, workspace); }
|
||||
function updateCode(event) { if (event.type == Blockly.Events.UI) return; const code = Blockly.Human.workspaceToCode(workspace); document.getElementById('codeOutput').value = code; }
|
||||
workspace.addChangeListener(updateCode);
|
||||
loadWorkspace();
|
||||
};
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
unit ApiKey;
|
||||
|
||||
interface
|
||||
|
||||
const Value = 'AIzaSyALccoMxn0_wcHswavhu5rzdglLeH6gVlI';
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
@@ -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.
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -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
|
||||
@@ -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<String>;
|
||||
FChatHistory: TList<TChatTurn>; // 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<TChatTurn>.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<string>.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<TJSONArray>('candidates')
|
||||
.Items[0].GetValue<TJSONObject>('content')
|
||||
.GetValue<TJSONArray>('parts')
|
||||
.Items[0].GetValue<string>('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.
|
||||
|
||||
@@ -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<T: record> = packed record
|
||||
TimeStamp: TDateTime;
|
||||
Data: T;
|
||||
end;
|
||||
|
||||
// Represents a generic data stream capable of providing sequential data chunks.
|
||||
IDataStream<T> = interface
|
||||
@@ -69,10 +64,16 @@ type
|
||||
procedure ClearCache;
|
||||
end;
|
||||
|
||||
// A generic record for a single time-stamped data entry.
|
||||
TAuraFileDataRecord<T: record> = packed record
|
||||
TimeStamp: TDateTime;
|
||||
Data: T;
|
||||
end;
|
||||
|
||||
IAuraDataServer<T: record> = interface(IDataServer<T>)
|
||||
['{481E27DE-DC58-49AF-B8A8-B6316980C423}']
|
||||
function LoadDataFile(const FileName: string): TFuture<TArray<TDataRecord<T>>>;
|
||||
function LoadDataSeries(const FileName: string): TFuture<TArray<TDataRecord<T>>>;
|
||||
function LoadDataFile(const FileName: string): TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
function LoadDataSeries(const FileName: string): TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
function EnumerateAssetFiles: TArray<String>;
|
||||
end;
|
||||
|
||||
@@ -87,7 +88,7 @@ type
|
||||
Name: String;
|
||||
Age: TDateTime;
|
||||
LastUsed: TDateTime;
|
||||
Data: TFuture<TArray<TDataRecord<T>>>;
|
||||
Data: TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
end;
|
||||
private
|
||||
// The cache is per-instance.
|
||||
@@ -101,8 +102,8 @@ type
|
||||
FLoadGate: TLatch;
|
||||
|
||||
protected
|
||||
class function ReadCompressedData(const InputStream: TStream): TArray<TDataRecord<T>>; static;
|
||||
class function ReadUncompressedData(const InputStream: TStream): TArray<TDataRecord<T>>; static;
|
||||
class function ReadCompressedData(const InputStream: TStream): TArray<TAuraFileDataRecord<T>>; static;
|
||||
class function ReadUncompressedData(const InputStream: TStream): TArray<TAuraFileDataRecord<T>>; static;
|
||||
|
||||
public
|
||||
constructor Create(const APath: String);
|
||||
@@ -123,8 +124,8 @@ type
|
||||
procedure ClearCache;
|
||||
function EnumerateAssetFiles: TArray<String>;
|
||||
|
||||
function LoadDataFile(const FileName: string): TFuture<TArray<TDataRecord<T>>>;
|
||||
function LoadDataSeries(const FileName: string): TFuture<TArray<TDataRecord<T>>>;
|
||||
function LoadDataFile(const FileName: string): TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
function LoadDataSeries(const FileName: string): TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
|
||||
property Path: String read GetPath;
|
||||
end;
|
||||
@@ -135,9 +136,9 @@ type
|
||||
FDataServer: TAuraDataServer<T>;
|
||||
FIsLiveData: TMutable<Boolean>.IWriteable;
|
||||
FCurrentFileName: string;
|
||||
FCurrentData: TFuture<TArray<TDataRecord<T>>>;
|
||||
FCurrentData: TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
FNextFileName: string;
|
||||
FNextData: TFuture<TArray<TDataRecord<T>>>;
|
||||
FNextData: TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
FCurrPosInFile: Int64;
|
||||
FCurrentIdx: Int64;
|
||||
FLastTimeStamp: TDateTime;
|
||||
@@ -314,12 +315,12 @@ begin
|
||||
Result := FPath;
|
||||
end;
|
||||
|
||||
function TAuraDataServer<T>.LoadDataFile(const FileName: string): TFuture<TArray<TDataRecord<T>>>;
|
||||
function TAuraDataServer<T>.LoadDataFile(const FileName: string): TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
var
|
||||
parsedPath, parsedSymbol: string;
|
||||
parsedYear, parsedMonth: Integer;
|
||||
begin
|
||||
Result := TFuture<TArray<TDataRecord<T>>>.Null;
|
||||
Result := TFuture<TArray<TAuraFileDataRecord<T>>>.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<TArray<TDataRecord<T>>>(
|
||||
function(bytes: TBytes): TArray<TDataRecord<T>>
|
||||
.Chain<TArray<TAuraFileDataRecord<T>>>(
|
||||
function(bytes: TBytes): TArray<TAuraFileDataRecord<T>>
|
||||
begin
|
||||
var zipMemoryStream := TBytesStream.Create(bytes);
|
||||
try
|
||||
@@ -383,9 +384,9 @@ begin
|
||||
else if TFile.Exists(FileName) then
|
||||
begin
|
||||
Result :=
|
||||
TFuture<TArray<TDataRecord<T>>>.Construct(
|
||||
TFuture<TArray<TAuraFileDataRecord<T>>>.Construct(
|
||||
TLatch.Enqueue(FLoadGate), // Use shared class var FLoadGate
|
||||
function: TArray<TDataRecord<T>>
|
||||
function: TArray<TAuraFileDataRecord<T>>
|
||||
begin
|
||||
if TFile.Exists(capFileName) then
|
||||
begin
|
||||
@@ -418,11 +419,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAuraDataServer<T>.LoadDataSeries(const FileName: string): TFuture<TArray<TDataRecord<T>>>;
|
||||
function TAuraDataServer<T>.LoadDataSeries(const FileName: string): TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
var
|
||||
loadedState: TState;
|
||||
loadedFiles: TArray<TFuture<TArray<TDataRecord<T>>>>;
|
||||
liveData: TFuture<TArray<TDataRecord<T>>>;
|
||||
loadedFiles: TArray<TFuture<TArray<TAuraFileDataRecord<T>>>>;
|
||||
liveData: TFuture<TArray<TAuraFileDataRecord<T>>>;
|
||||
tabFiles: TList<string>;
|
||||
currentFile: string;
|
||||
liveFilePath: string;
|
||||
@@ -452,7 +453,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
var loadedFileList := TList<TFuture<TArray<TDataRecord<T>>>>.Create;
|
||||
var loadedFileList := TList<TFuture<TArray<TAuraFileDataRecord<T>>>>.Create;
|
||||
var loadStates := TList<TState>.Create;
|
||||
try
|
||||
for currentFile in tabFiles do
|
||||
@@ -462,7 +463,7 @@ begin
|
||||
loadStates.Add(data.Done);
|
||||
end;
|
||||
|
||||
liveData := TFuture<TArray<TDataRecord<T>>>.Null;
|
||||
liveData := TFuture<TArray<TAuraFileDataRecord<T>>>.Null;
|
||||
if liveFilePath <> '' then
|
||||
begin
|
||||
liveData := LoadDataFile(liveFilePath);
|
||||
@@ -481,11 +482,11 @@ begin
|
||||
end;
|
||||
|
||||
Result :=
|
||||
TFuture<TArray<TDataRecord<T>>>.Construct(
|
||||
TFuture<TArray<TAuraFileDataRecord<T>>>.Construct(
|
||||
loadedState,
|
||||
function: TArray<TDataRecord<T>>
|
||||
function: TArray<TAuraFileDataRecord<T>>
|
||||
begin
|
||||
var tickList := TList<TDataRecord<T>>.Create;
|
||||
var tickList := TList<TAuraFileDataRecord<T>>.Create;
|
||||
try
|
||||
var overallLastTabTickTime: TDateTime := 0;
|
||||
var cnt := 0;
|
||||
@@ -508,7 +509,7 @@ begin
|
||||
);
|
||||
end;
|
||||
|
||||
class function TAuraDataServer<T>.ReadCompressedData(const InputStream: TStream): TArray<TDataRecord<T>>;
|
||||
class function TAuraDataServer<T>.ReadCompressedData(const InputStream: TStream): TArray<TAuraFileDataRecord<T>>;
|
||||
var
|
||||
decompressionStream: TStream;
|
||||
localHeader: TZipHeader;
|
||||
@@ -547,7 +548,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TAuraDataServer<T>.ReadUncompressedData(const InputStream: TStream): TArray<TDataRecord<T>>;
|
||||
class function TAuraDataServer<T>.ReadUncompressedData(const InputStream: TStream): TArray<TAuraFileDataRecord<T>>;
|
||||
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<T>)) <> 0) then
|
||||
if (fileSize = 0) or ((fileSize mod SizeOf(TAuraFileDataRecord<T>)) <> 0) then
|
||||
exit;
|
||||
|
||||
recordCount := fileSize div SizeOf(TDataRecord<T>);
|
||||
recordCount := fileSize div SizeOf(TAuraFileDataRecord<T>);
|
||||
if recordCount > 0 then
|
||||
begin
|
||||
SetLength(Result, recordCount);
|
||||
@@ -596,8 +597,8 @@ end;
|
||||
|
||||
function TAuraFileStream<T>.GetChunk(var Data: array of TDataPoint<T>): Integer;
|
||||
var
|
||||
item: TDataRecord<T>;
|
||||
currData: TArray<TDataRecord<T>>;
|
||||
item: TAuraFileDataRecord<T>;
|
||||
currData: TArray<TAuraFileDataRecord<T>>;
|
||||
begin
|
||||
Result := 0;
|
||||
if not FCurrentData.Done.IsSet then
|
||||
|
||||
Reference in New Issue
Block a user