unit Demos.TextAnalytics.Forms.Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.BaseImageCollection,
  Vcl.ImageCollection, System.Actions, Vcl.ActnList, Vcl.StdCtrls,
  Vcl.ControlList, Vcl.VirtualImage, Vcl.ExtCtrls, System.ImageList, Vcl.ImgList,
  Vcl.ComCtrls, Vcl.ToolWin, Vcl.ExtDlgs,
  Azure.CognitiveServices.Core.Entities,
  Azure.CognitiveServices.TextAnalytics.Types;

type

{ TMainForm }

  TMainForm = class(TForm)
    TextMemo: TMemo;
    SentimentImages: TImageCollection;
    MainImageList: TImageList;
    MainActionList: TActionList;
    LoadTextAction: TAction;
    AnalyzeTextAction: TAction;
    ClearDataAction: TAction;
    AppExitAction: TAction;
    MainToolbar: TToolBar;
    AppExitButton: TToolButton;
    OpenTextFileDialog: TOpenTextFileDialog;
    ResponsePanel: TGridPanel;
    SentimentPanel: TPanel;
    SentimentImage: TImage;
    SentimentLabel: TLabel;
    SentenceControlList: TControlList;
    SentenceLabel: TLabel;
    SentenceImage: TVirtualImage;
    SentenceButton: TControlListButton;
    ScorePanel: TPanel;
    ScorePositiveShape: TShape;
    ScorePositiveLabel: TLabel;
    ScoreNeutralShape: TShape;
    ScoreNeutralLabel: TLabel;
    ScoreNegativeShape: TShape;
    ScoreNegativeLabel: TLabel;
    MainSplitter: TSplitter;
    procedure MainActionListUpdate(Action: TBasicAction; var Handled: Boolean);
    procedure LoadTextActionExecute(Sender: TObject);
    procedure AnalyzeTextActionExecute(Sender: TObject);
    procedure ClearDataActionExecute(Sender: TObject);
    procedure AppExitActionExecute(Sender: TObject);
    procedure SentenceControlListBeforeDrawItem(AIndex: Integer;
      ACanvas: TCanvas; ARect: TRect; AState: TOwnerDrawState);
    procedure SentenceButtonClick(Sender: TObject);
  private
    FDocument: TAcsTextAnalyticsResponseDocument;
    function HasResponse: Boolean;
    function HasText: Boolean;
    procedure UpdateResponse();
  public
    constructor Create(AOwner: TComponent); override;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

uses
  System.IOUtils, System.Rtti,
  Azure.CognitiveServices.TextAnalytics.HTTP;

{ TMainForm }

constructor TMainForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  UpdateResponse();
end;

function TMainForm.HasResponse: Boolean;
begin
  Result := (Length(FDocument.ID) > 0) and (Length(FDocument.Sentences) > 0);
end;

function TMainForm.HasText: Boolean;
begin
  Result := Length(TextMemo.Lines.Text) > 0;
end;

procedure TMainForm.MainActionListUpdate(Action: TBasicAction;
  var Handled: Boolean);
begin
  LoadTextAction.Enabled := True;
  AnalyzeTextAction.Enabled := HasText;
  ClearDataAction.Enabled := HasResponse;
  Handled := True;
end;

procedure TMainForm.SentenceButtonClick(Sender: TObject);
begin
  var LSentenceIndex := SentenceControlList.ItemIndex;
  if LSentenceIndex < 0 then
    Exit;
  var LSentence := FDocument.Sentences[LSentenceIndex];
  var LText := TStringBuilder.Create;
  try
    LText
      .AppendLine('Sentiment:')
      .AppendLine(TRttiEnumerationType.GetName(LSentence.Sentiment))
      .AppendLine()
      .AppendLine('Confidence Scores:')
      .Append('  Positivo =')
      .AppendLine(Format('%.2f', [LSentence.ConfidenceScores.Positive]))
      .Append('  Neutrale =')
      .AppendLine(Format('%.2f', [LSentence.ConfidenceScores.Neutral]))
      .Append('  Negativo =')
      .AppendLine(Format('%.2f', [LSentence.ConfidenceScores.Negative]))
      .AppendLine()
      .AppendLine('Offset:')
      .Append(LSentence.Offset)
      .AppendLine().AppendLine()
      .AppendLine('Length:')
      .Append(LSentence.Length)
      .AppendLine().AppendLine()
      .AppendLine('Testo:')
      .Append(LSentence.Text);
    Application.MessageBox(PChar(LText.ToString), PChar(Application.Title),
      MB_ICONINFORMATION or MB_OK);
  finally
    LText.Free;
  end;
end;

procedure TMainForm.SentenceControlListBeforeDrawItem(AIndex: Integer;
  ACanvas: TCanvas; ARect: TRect; AState: TOwnerDrawState);
begin
  if Length(FDocument.Sentences) <= 0 then
    Exit;

  var LSentence := FDocument.Sentences[AIndex];

  SentenceImage.ImageName := TRttiEnumerationType.GetName(LSentence.Sentiment);
  SentenceLabel.Caption := LSentence.Text;
  SentenceLabel.Hint := LSentence.Text;
end;

procedure TMainForm.UpdateResponse();
begin
  if not HasResponse then
  begin
    ResponsePanel.Visible := False;
    Exit;
  end;

  var LSentimentName := TRttiEnumerationType.GetName(FDocument.Sentiment);

  var LSentimentBitmap := SentimentImages.GetBitmap(LSentimentName,
    SentimentImage.Width - 4, SentimentImage.Height - 4);
  try
    SentimentImage.Picture.Assign(LSentimentBitmap);
  finally
    LSentimentBitmap.Free;
  end;

  SentimentLabel.Caption := LSentimentName;

  with FDocument.ConfidenceScores do
  begin
    ScorePositiveLabel.Caption := Format('%.2f', [Positive]);
    ScoreNeutralLabel.Caption := Format('%.2f', [Neutral]);
    ScoreNegativeLabel.Caption := Format('%.2f', [Negative]);
  end;

  SentenceControlList.ItemCount := Length(FDocument.Sentences);

  ResponsePanel.Visible := True;
end;

procedure TMainForm.AnalyzeTextActionExecute(Sender: TObject);
var
  LConfig: IAcsConfiguration;
  LBroker: TAcsTextAnalyticsHttpBroker;
  LRequest: TAcsTextAnalyticsRequest;
  LResponse: TAcsTextAnalyticsResponse;
begin
  LConfig := LoadAcsConfiguration();

  with LRequest do
  begin
    SetLength(Documents, 1);
    LRequest.Documents[0].ID := TGUID.NewGuid.ToString();
    LRequest.Documents[0].Language := 'it';
    LRequest.Documents[0].Text := TextMemo.Lines.Text.Replace(#13#10, ' ');
  end;

  LBroker := TAcsTextAnalyticsHttpBroker.Create(LConfig);
  try
    LBroker.Endpoint := 'https://???.cognitiveservices.azure.com/text/analytics/v3.0/sentiment';
    LResponse := LBroker.Execute(LRequest);
  finally
    LBroker.Free;
  end;

  if Length(LResponse.Documents) <= 0 then
  begin
    ClearDataAction.Execute;
    Exit;
  end;

  FDocument := LResponse.Documents[0];

  UpdateResponse();
end;

procedure TMainForm.AppExitActionExecute(Sender: TObject);
begin
  Close();
end;

procedure TMainForm.ClearDataActionExecute(Sender: TObject);
begin
  FDocument.ID := EmptyStr;
  SetLength(FDocument.Sentences, 0);
  UpdateResponse();
end;

procedure TMainForm.LoadTextActionExecute(Sender: TObject);
begin
  if not OpenTextFileDialog.Execute() then
    Exit;

  with OpenTextFileDialog do
  begin
    var LEncoding := TEncoding.GetEncoding(Encodings[EncodingIndex]);
    try
      TextMemo.Lines.LoadFromFile(FileName, LEncoding);
    finally
      LEncoding.Free;
    end;
  end;

  ClearDataAction.Execute;
end;

end.
