Skip to content

Commit 5d20d3d

Browse files
committed
add-groq
1 parent 3bb7da5 commit 5d20d3d

9 files changed

+142
-53
lines changed

Package/DelphiAIDeveloper.dpk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ contains
7373
DelphiAIDev.DefaultsQuestions.PopupMenu in '..\Src\DefaultsQuestions\DelphiAIDev.DefaultsQuestions.PopupMenu.pas',
7474
DelphiAIDev.Utils.ABMenuAction in '..\Src\Utils\DelphiAIDev.Utils.ABMenuAction.pas',
7575
DelphiAIDev.IDE.Splash in '..\Src\IDE\Splash\DelphiAIDev.IDE.Splash.pas',
76-
DelphiAIDev.Chat.ProcessResponse in '..\Src\Chat\DelphiAIDev.Chat.ProcessResponse.pas';
76+
DelphiAIDev.Chat.ProcessResponse in '..\Src\Chat\DelphiAIDev.Chat.ProcessResponse.pas',
77+
DelphiAIDev.AI.Groq in '..\Src\AI\DelphiAIDev.AI.Groq.pas';
7778

7879
end.

Package/DelphiAIDeveloper.dproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@
180180
<DCCReference Include="..\Src\Utils\DelphiAIDev.Utils.ABMenuAction.pas"/>
181181
<DCCReference Include="..\Src\IDE\Splash\DelphiAIDev.IDE.Splash.pas"/>
182182
<DCCReference Include="..\Src\Chat\DelphiAIDev.Chat.ProcessResponse.pas"/>
183+
<DCCReference Include="..\Src\AI\DelphiAIDev.AI.Groq.pas"/>
183184
<RcItem Include="Img\c4d_gear.bmp">
184185
<ResourceType>BITMAP</ResourceType>
185186
<ResourceId>c4d_gear</ResourceId>

Src/AI/DelphiAIDev.AI.ChatGPT.pas

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ function TDelphiAIDevAIChatGPT.GetResponse(const AQuestion: string): string;
4242
LApiUrl: string;
4343
LQuestion: string;
4444
LResponse: IResponse;
45-
LReturnValue: TJSONValue;
46-
LChoicesValue: TJSONValue;
47-
LChoicesArray: TJSONArray;
48-
LChoicesObj: TJSONObject;
49-
LMessageValue: TJSONValue;
50-
LMessageObj: TJSONObject;
51-
I: Integer;
45+
LJsonValueAll: TJSONValue;
46+
LJsonValueChoices: TJSONValue;
47+
LJsonArrayChoices: TJSONArray;
48+
LJsonObjChoices: TJSONObject;
49+
LJsonValueMessage: TJSONValue;
50+
LJsonObjMessage: TJSONObject;
51+
LItemChoices: Integer;
5252
begin
5353
Result := '';
5454
LApiUrl := FSettings.BaseUrlOpenAI;
@@ -65,37 +65,33 @@ function TDelphiAIDevAIChatGPT.GetResponse(const AQuestion: string): string;
6565
if LResponse.StatusCode <> 200 then
6666
Exit('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
6767

68-
//TJSONValue COMPLETE
69-
LReturnValue := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LResponse.Content), 0);
70-
if not(LReturnValue is TJSONObject) then
68+
LJsonValueAll := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(LResponse.Content), 0);
69+
if not(LJsonValueAll is TJSONObject) then
7170
Exit('The question cannot be answered, return object not found.' + sLineBreak +
7271
'Return: ' + LResponse.Content);
7372

74-
//GET CHOICES LIKE TJSONValue
75-
LChoicesValue := TJSONObject(LReturnValue).GetValue('choices');
76-
77-
if not(LChoicesValue is TJSONArray) then
73+
LJsonValueChoices := TJSONObject(LJsonValueAll).GetValue('choices');
74+
if not(LJsonValueChoices is TJSONArray) then
7875
Exit('The question cannot be answered, choices not found.' + sLineBreak +
7976
'Return: ' + LResponse.Content);
8077

81-
//CAST CHOICES LIKE TJSONArray
82-
LChoicesArray := LChoicesValue as TJSONArray;
83-
for I := 0 to Pred(LChoicesArray.Count) do
78+
LJsonArrayChoices := LJsonValueChoices as TJSONArray;
79+
for LItemChoices := 0 to Pred(LJsonArrayChoices.Count) do
8480
begin
85-
if not(LChoicesArray.Items[I] is TJSONObject) then
81+
if not(LJsonArrayChoices.Items[LItemChoices] is TJSONObject) then
8682
Continue;
8783

8884
//CAST ITEM CHOICES LIKE TJSONObject
89-
LChoicesObj := LChoicesArray.Items[I] as TJSONObject;
85+
LJsonObjChoices := LJsonArrayChoices.Items[LItemChoices] as TJSONObject;
9086

9187
//GET MESSAGE LIKE TJSONValue
92-
LMessageValue := LChoicesObj.GetValue('message');
93-
if not(LMessageValue is TJSONObject) then
88+
LJsonValueMessage := LJsonObjChoices.GetValue('message');
89+
if not(LJsonValueMessage is TJSONObject) then
9490
Continue;
9591

9692
//GET MESSAGE LIKE TJSONObject
97-
LMessageObj := LMessageValue as TJSONObject;
98-
Result := Result + TJSONString(LMessageObj.GetValue('content')).Value + sLineBreak;
93+
LJsonObjMessage := LJsonValueMessage as TJSONObject;
94+
Result := Result + TJSONString(LJsonObjMessage.GetValue('content')).Value.Trim + sLineBreak;
9995
end;
10096

10197
Result := Result.Trim;

Src/AI/DelphiAIDev.AI.Gemini.pas

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,12 @@ function TDelphiAIDevAIGemini.GetResponse(const AQuestion: string): string;
4242
LApiUrl: string;
4343
LQuestion: string;
4444
LResponse: IResponse;
45-
LJsonValue: TJSONVALUE;
46-
LJsonArray: TJsonArray;
47-
LPartsArray: TJsonArray;
48-
LJsonObj: TJsonObject;
49-
LPartsObj: TJsonObject;
50-
LJsonText: string;
51-
i, j: Integer;
45+
LJsonValueAll: TJSONVALUE;
46+
LJsonArrayCandidates: TJsonArray;
47+
LJsonArrayParts: TJsonArray;
48+
LJsonObjContent: TJsonObject;
49+
LJsonObjParts: TJsonObject;
50+
LItemCandidates, LItemParts: Integer;
5251
begin
5352
Result := '';
5453
LApiUrl := FSettings.BaseUrlGemini + FSettings.ModelGemini + '?key=' + FSettings.ApiKeyGemini;
@@ -61,28 +60,26 @@ function TDelphiAIDevAIGemini.GetResponse(const AQuestion: string): string;
6160
.Post;
6261

6362
if LResponse.StatusCode <> 200 then
64-
begin
65-
Result := 'Question cannot be answered' + sLineBreak +
66-
'Return: ' + LResponse.Content;
67-
Exit;
68-
end;
63+
Exit('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
6964

70-
LJsonValue := TJsonObject.ParseJSONValue(LResponse.Content);
71-
if LJsonValue is TJsonObject then
65+
LJsonValueAll := TJsonObject.ParseJSONValue(LResponse.Content);
66+
if not(LJsonValueAll is TJSONObject) then
67+
Exit('The question cannot be answered, return object not found.' + sLineBreak +
68+
'Return: ' + LResponse.Content);
69+
70+
LJsonArrayCandidates := (LJsonValueAll as TJsonObject).GetValue<TJsonArray>('candidates');
71+
for LItemCandidates := 0 to Pred(LJsonArrayCandidates.Count) do
7272
begin
73-
LJsonArray := (LJsonValue as TJsonObject).GetValue<TJsonArray>('candidates');
74-
for i := 0 to Pred(LJsonArray.Count) do
73+
LJsonObjContent := LJsonArrayCandidates.Items[LItemCandidates].GetValue<TJsonObject>('content');
74+
LJsonArrayParts := LJsonObjContent.GetValue<TJsonArray>('parts');
75+
for LItemParts := 0 to Pred(LJsonArrayParts.Count) do
7576
begin
76-
LJsonObj := LJsonArray.Items[i].GetValue<TJsonObject>('content');
77-
LPartsArray := LJsonObj.GetValue<TJsonArray>('parts');
78-
for j := 0 to Pred(LPartsArray.Count) do
79-
begin
80-
LPartsObj := LPartsArray.Items[j] as TJsonObject;
81-
LJsonText := LPartsObj.GetValue<string>('text');
82-
Result := LJsonText.Trim;
83-
end;
77+
LJsonObjParts := LJsonArrayParts.Items[LItemParts] as TJsonObject;
78+
Result := Result + LJsonObjParts.GetValue<string>('text').Trim + sLineBreak;
8479
end;
8580
end;
81+
82+
Result := Result.Trim;
8683
end;
8784

8885
end.

Src/AI/DelphiAIDev.AI.Groq.pas

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
unit DelphiAIDev.AI.Groq;
2+
3+
interface
4+
5+
uses
6+
System.SysUtils,
7+
System.JSON,
8+
System.Classes,
9+
RESTRequest4D,
10+
DelphiAIDev.Utils,
11+
DelphiAIDev.Settings,
12+
DelphiAIDev.AI.Interfaces;
13+
14+
type
15+
TDelphiAIDevAIGroq = class(TInterfacedObject, IDelphiAIDevAI)
16+
private
17+
FSettings: TDelphiAIDevSettings;
18+
protected
19+
function GetResponse(const AQuestion: string): string;
20+
public
21+
class function New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
22+
constructor Create(const ASettings: TDelphiAIDevSettings);
23+
end;
24+
25+
implementation
26+
27+
const
28+
API_JSON_BODY_BASE = '{"messages": [{"role": "user", "content": "%s"}], "model": "%s"}';
29+
30+
class function TDelphiAIDevAIGroq.New(const ASettings: TDelphiAIDevSettings): IDelphiAIDevAI;
31+
begin
32+
Result := Self.Create(ASettings);
33+
end;
34+
35+
constructor TDelphiAIDevAIGroq.Create(const ASettings: TDelphiAIDevSettings);
36+
begin
37+
FSettings := ASettings;
38+
end;
39+
40+
function TDelphiAIDevAIGroq.GetResponse(const AQuestion: string): string;
41+
var
42+
LApiUrl: string;
43+
LQuestion: string;
44+
LResponse: IResponse;
45+
LJsonValueAll: TJSONVALUE;
46+
LJsonArrayChoices: TJsonArray;
47+
LJsonObjMessage: TJsonObject;
48+
LContent: string;
49+
LItemChoices: Integer;
50+
begin
51+
Result := '';
52+
//LApiUrl := FSettings.BaseUrlGemini + FSettings.ModelGemini + '?key=' + FSettings.ApiKeyGemini;
53+
LApiUrl := 'https://api.groq.com/openai/v1/chat/completions';
54+
LQuestion := TUtils.AdjustQuestionToJson(AQuestion);
55+
56+
LResponse := TRequest.New
57+
.BaseURL(LApiUrl)
58+
.ContentType('application/json')
59+
.Accept('application/json')
60+
//.Token('Bearer ' + FSettings.ApiKeyOpenAI)
61+
.Token('Bearer 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')
62+
//.AddBody(Format(API_JSON_BODY_BASE, [FSettings.ModelOpenAI, LQuestion]))
63+
.AddBody(Format(API_JSON_BODY_BASE, [LQuestion, 'Llama3-8b-8192']))
64+
.Post;
65+
66+
if LResponse.StatusCode <> 200 then
67+
Exit('Question cannot be answered' + sLineBreak + 'Return: ' + LResponse.Content);
68+
69+
LJsonValueAll := TJsonObject.ParseJSONValue(LResponse.Content);
70+
if not(LJsonValueAll is TJSONObject) then
71+
Exit('The question cannot be answered, return object not found.' + sLineBreak +
72+
'Return: ' + LResponse.Content);
73+
74+
LJsonArrayChoices := (LJsonValueAll as TJsonObject).GetValue<TJsonArray>('choices');
75+
for LItemChoices := 0 to Pred(LJsonArrayChoices.Count) do
76+
begin
77+
LJsonObjMessage := LJsonArrayChoices.Items[LItemChoices].GetValue<TJsonObject>('message');
78+
LContent := LJsonObjMessage.GetValue<string>('content');
79+
Result := Result + LContent.Trim + sLineBreak;
80+
end;
81+
82+
Result := Result.Trim;
83+
end;
84+
85+
end.

Src/Chat/DelphiAIDev.Chat.View.dfm

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -802,8 +802,8 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
802802
end
803803
object pMenuCurrentAI: TPopupMenu
804804
OnPopup = pMenuCurrentAIPopup
805-
Left = 26
806-
Top = 575
805+
Left = 50
806+
Top = 583
807807
object Gemini1: TMenuItem
808808
Caption = 'Gemini'
809809
OnClick = Gemini1Click
@@ -813,6 +813,11 @@ object DelphiAIDevChatView: TDelphiAIDevChatView
813813
Caption = 'ChatGPT'
814814
OnClick = Gemini1Click
815815
end
816+
object Groq1: TMenuItem
817+
Tag = 2
818+
Caption = 'Groq'
819+
OnClick = Gemini1Click
820+
end
816821
end
817822
object pMenuMoreActions: TPopupMenu
818823
Images = ImageList1

Src/Chat/DelphiAIDev.Chat.View.pas

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ TDelphiAIDevChatView = class(TDockableForm)
7373
btnDefaultsQuestions: TButton;
7474
pMenuQuestions: TPopupMenu;
7575
btnCleanAll: TSpeedButton;
76+
Groq1: TMenuItem;
7677
procedure FormShow(Sender: TObject);
7778
procedure cBoxSizeFontKeyPress(Sender: TObject; var Key: Char);
7879
procedure Cut1Click(Sender: TObject);
@@ -770,7 +771,7 @@ procedure TDelphiAIDevChatView.Gemini1Click(Sender: TObject);
770771
begin
771772
//*SEVERAL
772773
LTag := TMenuItem(Sender).Tag;
773-
if not(LTag in [0, 1])then
774+
if not(LTag in [0, 1, 2])then
774775
Exit;
775776

776777
FSettings.AIDefault := TC4DAIsAvailable(LTag);

Src/Chat/DelphiAIDev.Chat.pas

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ interface
88
DelphiAIDev.Types,
99
DelphiAIDev.Settings,
1010
DelphiAIDev.AI.Gemini,
11-
DelphiAIDev.AI.ChatGPT;
11+
DelphiAIDev.AI.ChatGPT,
12+
DelphiAIDev.AI.Groq;
1213

1314
type
1415
TDelphiAIDevChat = class
@@ -46,6 +47,8 @@ procedure TDelphiAIDevChat.ProcessSend(const AQuestion: string);
4647
FResponse.Text := TDelphiAIDevAIGemini.New(FSettings).GetResponse(AQuestion);
4748
TC4DAIsAvailable.OpenAI:
4849
FResponse.Text := TDelphiAIDevAIChatGPT.New(FSettings).GetResponse(AQuestion);
50+
TC4DAIsAvailable.Groq:
51+
FResponse.Text := TDelphiAIDevAIGroq.New(FSettings).GetResponse(AQuestion);
4952
else
5053
FResponse.Add('Default AI not reported in Delphi AI Developer settings');
5154
end;

Src/Types/DelphiAIDev.Types.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface
99

1010
type
1111
{$SCOPEDENUMS ON}
12-
TC4DAIsAvailable = (Gemini, OpenAI);
12+
TC4DAIsAvailable = (Gemini, OpenAI, Groq);
1313
TC4DLanguage = (en, ptBR, es);
1414
TC4DExtensionsFiles = (None, PAS, DFM, FMX, DPR, DPK, DPROJ, ZIP, BMP, INI, ALL);
1515
TC4DExtensionsOfFiles = set of TC4DExtensionsFiles;

0 commit comments

Comments
 (0)