1876 lines
54 KiB
ObjectPascal
1876 lines
54 KiB
ObjectPascal
{
|
||
получение доната
|
||
procedure TfrSettings.HandleWSDonate(aNick, aMessage, aSum: string);
|
||
|
||
получение сообщения
|
||
procedure TTTW_Bot.ttwIRCOnMessageRecord(aRecord: TTwitchChatMessage);
|
||
|
||
получение событий
|
||
ttw_ES.OnFollow := frOBS1.toEventWebServer;
|
||
ttw_ES.OnSub := frOBS1.toEventWebServer;
|
||
ttw_ES.OnGift := frOBS1.toEventWebServer;
|
||
ttw_ES.OnRaid := frOBS1.toEventWebServer;
|
||
}
|
||
|
||
unit uGeneral;
|
||
|
||
interface
|
||
|
||
uses
|
||
System.SysUtils, System.Types, System.UITypes, System.Classes, DateUtils,
|
||
System.Variants, uTTWIRC, uTTWEventSub, uTTWAPI, uSoundManager, uKeyEvent,
|
||
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.TabControl,
|
||
FMX.Controls.Presentation, FMX.StdCtrls, System.ImageList, FMX.ImgList,
|
||
FMX.Styles, ShellAPI, StrUtils, IdComponent, uRegExpr, uCustomEmoties,
|
||
fSettings, fAI, fNotify, fAutoActions, FMX.ListBox, fLog, fEvents,
|
||
System.Generics.Collections, utts, uGigaChat, uChatAPI, uMyTimer, uRecords,
|
||
System.IOUtils, fCommands, uDataBase, FMX.Edit, FMX.Colors, FMX.SpinBox,
|
||
windows, System.Skia, FMX.Skia, uCreateChat, uCreateNotify, fOBS, fTTS,
|
||
fPlayerWeb, uWebServerKandinsky, FMX.Memo.Types, FMX.ScrollBox, FMX.Memo,
|
||
fRevards, json;
|
||
|
||
type
|
||
TTTW_Bot = class(TForm)
|
||
V: TTabControl;
|
||
TabItem1: TTabItem;
|
||
TabItem2: TTabItem;
|
||
TabItem3: TTabItem;
|
||
TabItem4: TTabItem;
|
||
frSettings1: TfrSettings;
|
||
ImageList1: TImageList;
|
||
TabItem5: TTabItem;
|
||
Panel1: TPanel;
|
||
btnConnecting: TButton;
|
||
Label2: TLabel;
|
||
Label3: TLabel;
|
||
Label5: TLabel;
|
||
Label6: TLabel;
|
||
Label7: TLabel;
|
||
Label8: TLabel;
|
||
aiConnecting: TAniIndicator;
|
||
Label9: TLabel;
|
||
Label10: TLabel;
|
||
Label11: TLabel;
|
||
Label12: TLabel;
|
||
frAI1: TfrAI;
|
||
TabItem6: TTabItem;
|
||
TabItem7: TTabItem;
|
||
TabItem8: TTabItem;
|
||
TabItem9: TTabItem;
|
||
frNotify1: TfrNotify;
|
||
Label1: TLabel;
|
||
frAutoActions1: TfrAutoActions;
|
||
frOBS1: TfrOBS;
|
||
frLog1: TfrLog;
|
||
cbTheme: TComboBox;
|
||
Label15: TLabel;
|
||
frCommands1: TfrCommands;
|
||
SpeedButton1: TSpeedButton;
|
||
SpeedButton2: TSpeedButton;
|
||
SpeedButton3: TSpeedButton;
|
||
btnCreateChat: TButton;
|
||
frTTS1: TfrTTS;
|
||
GroupBox1: TGroupBox;
|
||
frPlayerWeb1: TfrPlayerWeb;
|
||
frEvents1: TfrEvents;
|
||
GroupBox2: TGroupBox;
|
||
GroupBox3: TGroupBox;
|
||
frRevards1: TfrRevards;
|
||
procedure cbThemeChange(Sender: TObject);
|
||
procedure FormCreate(Sender: TObject);
|
||
procedure SpeedButton1Click(Sender: TObject);
|
||
procedure SpeedButton3Click(Sender: TObject);
|
||
procedure SpeedButton2Click(Sender: TObject);
|
||
procedure frSettings1btnDAStartClick(Sender: TObject);
|
||
procedure frCommands1btnRandAddClick(Sender: TObject);
|
||
procedure frOBS1btnDeleteeChatClick(Sender: TObject);
|
||
procedure FormDestroy(Sender: TObject);
|
||
|
||
procedure frTTS1btnSendClick(Sender: TObject);
|
||
procedure btnConnectingClick(Sender: TObject);
|
||
procedure frAutoActions1btnCounterAddClick(Sender: TObject);
|
||
procedure frAutoActions1btnCounterEditClick(Sender: TObject);
|
||
procedure frAutoActions1btnCounterDeleteClick(Sender: TObject);
|
||
private
|
||
{ Private declarations }
|
||
procedure toSpeech(aText: string);
|
||
procedure OnTTWStatus(ASender: TObject; const AStatus: TIdStatus;
|
||
const AStatusText: string);
|
||
procedure ttwIRCOnMessageRecord(aRecord: TTwitchChatMessage);
|
||
procedure PlayNotifySound(aMod, aVip, aSub: Boolean);
|
||
procedure CheckBannedWords(const aText, dname, aID: string);
|
||
procedure ReadDB();
|
||
function PreprocessMessageText(const aText: string): string;
|
||
procedure UpdateWordCounters(const aText: string);
|
||
procedure decodeResponseSendToTTW(aResponseText, aCommandText,
|
||
adName: string);
|
||
function Pars(T_, text, _T: string): string;
|
||
procedure gptError(Msg: string);
|
||
function ResponsParserGroups(inMess: string): string;
|
||
function ResponsParserRandoms(inMess: string): string;
|
||
function ResponsParserCounters(inMess: string): string;
|
||
function ResponsParserStatic(inMess, adName, aCommandText: string): string;
|
||
function ResponsParserAPI(inMess, adName: string): string;
|
||
function ResponsParserGPT(inMess, aCommandText: string): string;
|
||
function ResponsParserAIGen(inMess, aCommandText: string): string;
|
||
function ResponsParserAIPic(inMess, aCommandText, aNick: string): string;
|
||
function ResponsParserSounds(inMess: string): string;
|
||
function ResponsParserText(inMess: string): string;
|
||
function ValidateInput: Boolean;
|
||
procedure ConnectProcedure;
|
||
procedure DisconnectProcedure;
|
||
procedure HandleTimers(Start: Boolean);
|
||
procedure ESError(aMsg: string);
|
||
procedure ESStatus(Sender: TObject; const ConnectionEvent: String;
|
||
StatusCode: Integer; const Description: String);
|
||
procedure ESOnSubOk(s: string);
|
||
procedure checkAndSendToGames(aNick: string; aCommand: string);
|
||
public
|
||
{ Public declarations }
|
||
procedure toLog(aModule, aMethod, aMessage: string; aCode: Integer);
|
||
function FindUserRow(const aNick: string): Integer;
|
||
procedure GlobalExceptionHandler(Sender: TObject; E: Exception);
|
||
end;
|
||
|
||
var
|
||
TTW_Bot: TTTW_Bot;
|
||
myConst: TConst;
|
||
db: TSettingsDatabase;
|
||
appconst: TBotAppCfg;
|
||
ttw_IRS: TTTW;
|
||
ttw_ES: TTTW_ES;
|
||
ttw_API: TTTW_API;
|
||
userlist: TList<TUser>;
|
||
Kandinsky: TKandinsky_Web;
|
||
kePoints: TKE;
|
||
|
||
implementation
|
||
|
||
{$R *.fmx}
|
||
|
||
procedure TTTW_Bot.HandleTimers(Start: Boolean);
|
||
var
|
||
I: Integer;
|
||
begin
|
||
for I := 0 to high(frAutoActions1.listTimer) do
|
||
begin
|
||
if Assigned(frAutoActions1.FTimerList[I]) then
|
||
begin
|
||
if Start and (frAutoActions1.listTimer[I].Enable = 1) then
|
||
frAutoActions1.FTimerList[I].StartT
|
||
else
|
||
frAutoActions1.FTimerList[I].StopT;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.toSpeech(aText: string);
|
||
var
|
||
tts: ttts;
|
||
s, s1: string;
|
||
begin
|
||
s := ExtractFilePath(ParamStr(0)) + 'piper\piper.exe';
|
||
s1 := ExtractFilePath(ParamStr(0)) + 'piper\voices';
|
||
if frTTS1.cbVoices.ItemIndex = -1 then
|
||
exit;
|
||
tts := ttts.Create(s, s1);
|
||
try
|
||
tts.SetModel(frTTS1.cbVoices.text);
|
||
tts.TextToSpeech(aText, true);
|
||
finally
|
||
tts.Free;
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.GlobalExceptionHandler(Sender: TObject; E: Exception);
|
||
begin
|
||
try
|
||
TTW_Bot.toLog('GlobalException', E.ClassName, E.Message, 2);
|
||
except
|
||
// на случай, если логгер сам кинет исключение
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.ConnectProcedure;
|
||
var
|
||
rid: string;
|
||
BotToken, StreamerToken: string;
|
||
dol: Integer;
|
||
begin
|
||
BotToken := frSettings1.edtBotToken.text;
|
||
StreamerToken := frSettings1.edtBotTokenStreamer.text;
|
||
|
||
// Проверка бот-токена
|
||
if not ttw_API.ValidateTwitchToken('Бот', BotToken, dol) then
|
||
raise Exception.Create('Недействительный бот-токен');
|
||
Label12.text := inttostr(dol);
|
||
// Проверка стример-токена (если отличается)
|
||
if (BotToken <> StreamerToken) and not ttw_API.ValidateTwitchToken('Стример',
|
||
StreamerToken, dol) then
|
||
raise Exception.Create('Недействительный стример-токен');
|
||
Label11.text := inttostr(dol);
|
||
// Инициализация и подключение основного сервиса
|
||
ttw_IRS.Init(frSettings1.edtBotToken.text, frSettings1.edtChannel.text,
|
||
frSettings1.edtBotName.text);
|
||
|
||
ttw_IRS.Connect;
|
||
|
||
// Инициализация API
|
||
try
|
||
ttw_API.Init(frSettings1.edtBotClientID.text, frSettings1.edtBotToken.text,
|
||
IfThen(frSettings1.edtBotTokenStreamer.text = '',
|
||
frSettings1.edtBotToken.text, frSettings1.edtBotTokenStreamer.text),
|
||
frSettings1.edtChannel.text, frSettings1.edtBotName.text);
|
||
except
|
||
on E: Exception do
|
||
begin
|
||
toLog('uGeneral', 'ConnectProcedure.ttw_API.Init', E.Message, 2);
|
||
|
||
end;
|
||
end;
|
||
|
||
// Обработка ролей
|
||
|
||
rid := ttw_API.getRoomAndBot;
|
||
if rid = '' then
|
||
raise Exception.Create('Не удалось получить Room ID');
|
||
try
|
||
frRevards1.LoadCustomRevards;
|
||
except
|
||
on E: Exception do
|
||
begin
|
||
toLog('uGeneral', 'ConnectProcedure.LoadCustomRevards', E.Message, 2);
|
||
end;
|
||
end;
|
||
// Загрузка эмодзи и бейджей
|
||
try
|
||
frOBS1.ChatBadges.Clear;
|
||
ttw_API.getCustomChatBadges(frOBS1.ChatBadges);
|
||
ttw_API.getGlobalChatBadges(frOBS1.ChatBadges);
|
||
|
||
frOBS1.ChatEmotes.Clear;
|
||
ttw_API.GetChannelEmotes(frOBS1.ChatEmotes);
|
||
ttw_API.GetGlobalEmotes(frOBS1.ChatEmotes);
|
||
|
||
frOBS1.BTTV.getGlobal;
|
||
frOBS1.BTTV.getCustom(rid);
|
||
|
||
frOBS1.m7tv.getGlobal;
|
||
frOBS1.m7tv.getCustom(rid);
|
||
except
|
||
on E: Exception do
|
||
begin
|
||
toLog('uGeneral', 'ConnectProcedure.Emotes', E.Message, 2);
|
||
|
||
end;
|
||
end;
|
||
|
||
// Инициализация EventSub
|
||
|
||
try
|
||
if Assigned(ttw_ES) then
|
||
FreeAndNil(ttw_ES);
|
||
|
||
ttw_ES := TTTW_ES.Create(Self, frSettings1.edtBotTokenStreamer.text,
|
||
frSettings1.edtBotClientID.text, rid);
|
||
|
||
// Назначение обработчиков событий
|
||
ttw_ES.OnLog := toLog;
|
||
ttw_ES.OnError := ESError;
|
||
ttw_ES.OnGetCustomReward := frEvents1.ESOnGetCustomReward;
|
||
ttw_ES.OnStatus := ESStatus;
|
||
// ttw_ES.OnRAW := fRewards.ESOnRAW;
|
||
ttw_ES.OnSubOk := ESOnSubOk;
|
||
ttw_ES.OnFollow := frOBS1.toEventWebServer;
|
||
ttw_ES.OnSub := frOBS1.toEventWebServer;
|
||
ttw_ES.OnGift := frOBS1.toEventWebServer;
|
||
ttw_ES.OnRaid := frOBS1.toEventWebServer;
|
||
toLog('uGeneral', 'ConnectProcedure.ttw_ES', 'Создан', 0);
|
||
ttw_ES.Connect;
|
||
except
|
||
on E: Exception do
|
||
begin
|
||
toLog('uGeneral', 'ConnectProcedure.ttw_ES', E.Message, 2);
|
||
|
||
end;
|
||
end;
|
||
|
||
HandleTimers(true);
|
||
|
||
if frSettings1.cbDAAutoLogin.IsChecked then
|
||
begin
|
||
frSettings1.btnDAGetCodeClick(Self);
|
||
end;
|
||
|
||
end;
|
||
|
||
procedure TTTW_Bot.DisconnectProcedure;
|
||
|
||
begin
|
||
try
|
||
toLog('DisconnectProcedure', 'Start', 'Начало процедуры отключения', 3);
|
||
// 1. Отключаем IRS
|
||
toLog('DisconnectProcedure', 'ttw_IRS.Disconnect',
|
||
'Попытка отключения IRS', 3);
|
||
ttw_IRS.Disconnect;
|
||
// 2. Обрабатываем EventSub
|
||
if Assigned(ttw_ES) then
|
||
begin
|
||
toLog('DisconnectProcedure', 'ttw_ES.Disconnect',
|
||
'Попытка отключения ES', 3);
|
||
ttw_ES.Disconnect;
|
||
|
||
// Даем время на корректное завершение
|
||
Sleep(150);
|
||
toLog('DisconnectProcedure', 'ttw_ES.Free', 'Освобождение ES', 3);
|
||
FreeAndNil(ttw_ES);
|
||
end;
|
||
// 3. Очищаем интерфейс
|
||
{ if Assigned(fChatFrame) then
|
||
begin
|
||
fChatFrame.ChatBadges.Clear;
|
||
fChatFrame.ChatEmotes.Clear;
|
||
{ for I := 0 to fChatFrame.ChatWebServers.Count - 1 do
|
||
begin
|
||
fChatFrame.ChatWebServers[I].WebServerChat.ActiveServer(false);
|
||
end;
|
||
end; }
|
||
// 4. Останавливаем таймеры
|
||
HandleTimers(false);
|
||
|
||
frSettings1.FWSClient.Disconnect;
|
||
|
||
Label3.text := 'Disconnected';
|
||
Label6.text := 'Disconnected';
|
||
except
|
||
on E: Exception do
|
||
toLog('DisconnectProcedure', 'General', E.ClassName + ': ' +
|
||
E.Message, 2);
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.ESError(aMsg: string);
|
||
begin
|
||
toLog('uGeneral', 'ESError', aMsg, 2);
|
||
end;
|
||
|
||
procedure TTTW_Bot.ESOnSubOk(s: string);
|
||
begin
|
||
toLog('uGeneral', 'ESOnSubOk', s, 0);
|
||
end;
|
||
|
||
procedure TTTW_Bot.ESStatus(Sender: TObject; const ConnectionEvent: String;
|
||
StatusCode: Integer; const Description: String);
|
||
begin
|
||
|
||
Label6.text := ConnectionEvent;
|
||
end;
|
||
|
||
function TTTW_Bot.ValidateInput: Boolean;
|
||
begin
|
||
Result := false;
|
||
|
||
if Trim(frSettings1.edtBotToken.text) = '' then
|
||
begin
|
||
ShowMessage('Токен бота обязателен для заполнения!');
|
||
exit;
|
||
end;
|
||
|
||
if Trim(frSettings1.edtChannel.text) = '' then
|
||
begin
|
||
ShowMessage('Название канала обязательно для заполнения!');
|
||
exit;
|
||
end;
|
||
|
||
if (Trim(frSettings1.edtBotClientID.text) = '') then
|
||
begin
|
||
ShowMessage('Client ID обязателен!');
|
||
exit;
|
||
end;
|
||
|
||
Result := true;
|
||
end;
|
||
|
||
procedure TTTW_Bot.btnConnectingClick(Sender: TObject);
|
||
|
||
begin
|
||
if not ValidateInput then
|
||
exit;
|
||
|
||
btnConnecting.Enabled := false;
|
||
aiConnecting.Enabled := true;
|
||
aiConnecting.Visible := true;
|
||
|
||
try
|
||
if btnConnecting.text = 'Подключиться' then
|
||
ConnectProcedure
|
||
else
|
||
DisconnectProcedure;
|
||
|
||
TThread.Synchronize(nil,
|
||
procedure
|
||
begin
|
||
btnConnecting.text := IfThen(btnConnecting.text = 'Подключиться',
|
||
'Отключиться', 'Подключиться');
|
||
end);
|
||
except
|
||
on E: Exception do
|
||
|
||
ShowMessage('Ошибка подключения: ' + E.Message);
|
||
end;
|
||
|
||
aiConnecting.Enabled := false;
|
||
aiConnecting.Visible := false;
|
||
btnConnecting.Enabled := true;
|
||
|
||
end;
|
||
|
||
procedure TTTW_Bot.cbThemeChange(Sender: TObject);
|
||
begin
|
||
cbTheme.ItemIndex := cbTheme.Items.IndexOf(cbTheme.text);
|
||
if cbTheme.ItemIndex <> -1 then
|
||
TStyleManager.SetStyleFromFile(myConst.stlPath + cbTheme.text);
|
||
db.WriteSetting('cbTheme', inttostr(cbTheme.ItemIndex));
|
||
end;
|
||
|
||
procedure TTTW_Bot.checkAndSendToGames(aNick: string; aCommand: string);
|
||
var
|
||
I: Integer;
|
||
j: Integer; s:string;
|
||
begin
|
||
for I := 0 to frOBS1.GameWebServers.Count - 1 do
|
||
begin
|
||
for j := 0 to frOBS1.GameWebServers[I].commands.Count - 1 do
|
||
begin
|
||
s:= frOBS1.GameWebServers[I].commands[j];
|
||
if s= aCommand.Trim then
|
||
begin
|
||
var
|
||
obj := TJSONObject.Create;
|
||
obj.AddPair('user', aNick);
|
||
obj.AddPair('cmd', aCommand.Trim);
|
||
frOBS1.GameWebServers[I].WebServerGame.Input(obj);
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.FormCreate(Sender: TObject);
|
||
var
|
||
Path: string;
|
||
|
||
function GetPathToTestExe: string; // вернет папку romaming
|
||
begin
|
||
Result := GetEnvironmentVariable('APPDATA');
|
||
if Result <> '' then
|
||
Result := IncludeTrailingPathDelimiter(Result);
|
||
end;
|
||
|
||
begin
|
||
|
||
myConst.GeneralPath := ExtractFilePath(ParamStr(0));
|
||
myConst.AppDataPath := GetPathToTestExe + 'TTW_Bot\';
|
||
|
||
if not DirectoryExists(myConst.AppDataPath) then
|
||
CreateDir(myConst.AppDataPath);
|
||
|
||
myConst.DBPath := myConst.AppDataPath + 'settings.db';
|
||
|
||
if not DirectoryExists(myConst.AppDataPath + 'fonts') then
|
||
CreateDir(myConst.AppDataPath + 'fonts');
|
||
myConst.fontsPath := myConst.AppDataPath + 'fonts\';
|
||
|
||
if not DirectoryExists(myConst.AppDataPath + 'imgs') then
|
||
CreateDir(myConst.AppDataPath + 'imgs');
|
||
myConst.imgsPath := myConst.AppDataPath + 'imgs\';
|
||
|
||
if not DirectoryExists(myConst.AppDataPath + 'sounds') then
|
||
CreateDir(myConst.AppDataPath + 'sounds');
|
||
myConst.soundsPath := myConst.AppDataPath + 'sounds\';
|
||
|
||
if not DirectoryExists(myConst.AppDataPath + 'stl') then
|
||
CreateDir(myConst.AppDataPath + 'stl');
|
||
myConst.stlPath := myConst.AppDataPath + 'stl\';
|
||
|
||
if not DirectoryExists(myConst.AppDataPath + 'ytSongs') then
|
||
CreateDir(myConst.AppDataPath + 'ytSongs');
|
||
myConst.ytSongsPath := myConst.AppDataPath + 'ytSongs\';
|
||
|
||
myConst.SilentPlay := myConst.GeneralPath + 'SilentPlayer.exe';
|
||
myConst.ytPlay := myConst.GeneralPath + 'Player.exe';
|
||
myConst.cfg1 := myConst.GeneralPath + 'botapp.cfg';
|
||
|
||
db := TSettingsDatabase.Create(myConst.DBPath);
|
||
frAutoActions1.FTimerList := TObjectList<TMyTimerThread>.Create(false);
|
||
ReadDB;
|
||
frCommands1.frsgSounds.ObjectRecord := frCommands1.listSounds;
|
||
frCommands1.frsgSounds.TableName := 'listSounds';
|
||
frCommands1.frsgSounds.UpdateGrid;
|
||
frCommands1.frsgFiles.ObjectRecord := frCommands1.listFiles;
|
||
frCommands1.frsgFiles.TableName := 'listFiles';
|
||
frCommands1.frsgFiles.UpdateGrid;
|
||
frCommands1.frsgNeiro.ObjectRecord := frCommands1.listNeiro;
|
||
frCommands1.frsgNeiro.TableName := 'listNeiro';
|
||
frCommands1.frsgNeiro.UpdateGrid;
|
||
|
||
for Path in TDirectory.GetFiles(myConst.stlPath) do
|
||
cbTheme.Items.Add(ExtractFileName(Path));
|
||
cbTheme.ItemIndex := strtoint(db.ReadSetting('cbTheme', '-1'));
|
||
frLog1.FLogList := TList<TRLog>.Create;
|
||
|
||
frPlayerWeb1.Init;
|
||
|
||
userlist := TList<TUser>.Create;
|
||
ttw_IRS := TTTW.Create(Self);
|
||
ttw_IRS.OnMessageRecord := ttwIRCOnMessageRecord;
|
||
ttw_IRS.OnLog := toLog;
|
||
ttw_IRS.OnStatus := OnTTWStatus;
|
||
|
||
ttw_API := TTTW_API.Create(Self);
|
||
|
||
end;
|
||
|
||
procedure TTTW_Bot.OnTTWStatus(ASender: TObject; const AStatus: TIdStatus;
|
||
const AStatusText: string);
|
||
begin
|
||
Label3.text := AStatusText;
|
||
end;
|
||
|
||
procedure TTTW_Bot.FormDestroy(Sender: TObject);
|
||
begin
|
||
FreeAndNil(frOBS1.ChatBadges);
|
||
FreeAndNil(frOBS1.ChatEmotes);
|
||
FreeAndNil(frOBS1.ChatWebServers);
|
||
FreeAndNil(frOBS1.EventWebServers);
|
||
FreeAndNil(frOBS1.KandinskyWebServers);
|
||
FreeAndNil(frOBS1.GameWebServers);
|
||
FreeAndNil(frRevards1.CustomRewards);
|
||
|
||
frOBS1.BTTV.Free;
|
||
frOBS1.m7tv.Free;
|
||
userlist.Free;
|
||
kePoints.Free;
|
||
|
||
DisconnectProcedure;
|
||
FreeAndNil(ttw_IRS);
|
||
FreeAndNil(ttw_ES);
|
||
FreeAndNil(ttw_API);
|
||
if Assigned(Kandinsky) then
|
||
Kandinsky.Free;
|
||
// frSettings1.Destroy;
|
||
FreeAndNil(db);
|
||
FreeAndNil(frAutoActions1.FTimerList);
|
||
FreeAndNil(frLog1.FLogList);
|
||
inherited;
|
||
end;
|
||
|
||
function TTTW_Bot.FindUserRow(const aNick: string): Integer;
|
||
var
|
||
I: Integer;
|
||
begin
|
||
Result := -1;
|
||
for I := 0 to userlist.Count - 1 do
|
||
if userlist[I].login = LowerCase(aNick) then
|
||
begin
|
||
Result := I;
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TTTW_Bot.PreprocessMessageText(const aText: string): string;
|
||
begin
|
||
Result := LowerCase(aText);
|
||
Result := StringReplace(Result, #$D, '', [rfReplaceAll]);
|
||
Result := StringReplace(Result, '', '', [rfReplaceAll]);
|
||
Result := Trim(Result) + ' ';
|
||
end;
|
||
|
||
procedure TTTW_Bot.UpdateWordCounters(const aText: string);
|
||
var
|
||
I: Integer;
|
||
Words: TArray<string>;
|
||
mode: Boolean;
|
||
|
||
procedure IncrementCounter(ARow: Integer);
|
||
var
|
||
Count: Integer;
|
||
begin
|
||
Count := frAutoActions1.listCounters[ARow].Count + 1;
|
||
frAutoActions1.listCounters[ARow].Count := Count;
|
||
db.SaveRecordArray<TCounter>('listCounters', frAutoActions1.listCounters);
|
||
frAutoActions1.UpdateGridFromArray;
|
||
end;
|
||
|
||
function StringToArray(const Input: string): TArray<string>;
|
||
var
|
||
Delimiter: char;
|
||
Words: TArray<string>;
|
||
I: Integer;
|
||
begin
|
||
Delimiter := ',';
|
||
Words := Input.Split([Delimiter]);
|
||
SetLength(Result, Length(Words));
|
||
for I := 0 to High(Words) do
|
||
Result[I] := Words[I].Trim;
|
||
end;
|
||
|
||
function ContainsAnyWord(const str: string;
|
||
const Words: array of string): Boolean;
|
||
var
|
||
I: Integer;
|
||
begin
|
||
for I := Low(Words) to High(Words) do
|
||
begin
|
||
if Pos(AnsiLowerCase(Words[I]), AnsiLowerCase(str)) > 0 then
|
||
begin
|
||
Result := true;
|
||
exit;
|
||
end;
|
||
end;
|
||
Result := false;
|
||
end;
|
||
|
||
begin
|
||
for I := 0 to high(frAutoActions1.listCounters) do
|
||
begin
|
||
mode := frAutoActions1.listCounters[I].auto = 1;
|
||
if mode then
|
||
begin
|
||
Words := StringToArray(frAutoActions1.listCounters[I].trigger);
|
||
if ContainsAnyWord(aText, Words) then
|
||
IncrementCounter(I);
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.CheckBannedWords(const aText, dname, aID: string);
|
||
var
|
||
I: Integer;
|
||
rx: TRegExpr;
|
||
begin
|
||
rx := TRegExpr.Create;
|
||
try
|
||
for I := 0 to high(frAutoActions1.listBanWords) do
|
||
begin
|
||
rx.Expression := frAutoActions1.listBanWords[I].regexp;
|
||
if rx.Exec(aText) then
|
||
begin
|
||
if aID = '0' then
|
||
ttw_API.banUserTime(dname, 86400)
|
||
else
|
||
ttw_API.banUserTime(aID, 86400);
|
||
Break;
|
||
end;
|
||
end;
|
||
finally
|
||
rx.Free;
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.ttwIRCOnMessageRecord(aRecord: TTwitchChatMessage);
|
||
// обработка нового сообщения
|
||
var
|
||
processedText: string;
|
||
firstWord: string;
|
||
commandText: string;
|
||
responseText, s: string;
|
||
u: TUser;
|
||
I: Integer;
|
||
|
||
function ExtractFirstWord(var aText: string): string;
|
||
var
|
||
posSpace: Integer;
|
||
begin
|
||
posSpace := Pos(' ', aText);
|
||
if posSpace > 0 then
|
||
begin
|
||
Result := Copy(aText, 1, posSpace - 1);
|
||
Result := StringReplace(Result, ',', '', [rfReplaceAll]);
|
||
Result := StringReplace(Result, '.', '', [rfReplaceAll]);
|
||
Result := StringReplace(Result, '?', '', [rfReplaceAll]);
|
||
end
|
||
else
|
||
Result := aText;
|
||
end;
|
||
function IsCommand(const aWord: string): Boolean;
|
||
begin
|
||
Result := (Length(aWord) > 0) and (aWord[1] = '!');
|
||
end;
|
||
|
||
function ExtractCommandText(const aText, aFirstWord: string): string;
|
||
begin
|
||
Result := Copy(aText, Length(aFirstWord) + 1, Length(aText));
|
||
end;
|
||
|
||
function ProcessCommand(const aCommand: string): string;
|
||
var
|
||
I: Integer;
|
||
begin
|
||
Result := '';
|
||
for I := 0 to high(frCommands1.listCommands) do
|
||
begin
|
||
if ContainsText(aCommand, frCommands1.listCommands[I].R1) then
|
||
begin
|
||
Result := frCommands1.listCommands[I].R2;
|
||
Break;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
begin
|
||
if aRecord.Username = '' then
|
||
exit;
|
||
I := FindUserRow(aRecord.Username);
|
||
if I <> -1 then
|
||
begin // user есть
|
||
u := userlist[I];
|
||
end
|
||
else
|
||
begin
|
||
u.ID := aRecord.UserId;
|
||
u.login := aRecord.Username;
|
||
u.isVIP := false;
|
||
u.isModer := false;
|
||
u.isO := false;
|
||
u.created_at := StrToDate('01.01.1990');
|
||
u.follow_at := StrToDate('01.01.1990');
|
||
u.isO_today := false;
|
||
userlist.Add(u);
|
||
end;
|
||
I := FindUserRow(aRecord.Username);
|
||
if (u.isO) and (NOT u.isO_today) then
|
||
begin
|
||
ttw_API.shoutouts(u.ID);
|
||
u.isO_today := true;
|
||
end;
|
||
userlist[I] := u;
|
||
|
||
processedText := PreprocessMessageText(aRecord.Message);
|
||
UpdateWordCounters(processedText);
|
||
CheckBannedWords(processedText, aRecord.DisplayName, aRecord.UserId);
|
||
|
||
if (frCommands1.frContruct1.cbTextToSpeach.IsChecked) and
|
||
(processedText[1] = '!') and (processedText[2] = '!') and
|
||
(processedText[3] = '!') then
|
||
begin
|
||
s := StringReplace(processedText, '!!!', '', [rfReplaceAll]);
|
||
s := Trim(s);
|
||
toSpeech(s);
|
||
exit;
|
||
end;
|
||
|
||
if (frCommands1.frContruct1.cbHelloTTS.IsChecked) and (aRecord.FirstMsg = 1)
|
||
then
|
||
toSpeech('приветствую, ' + IfThen(aRecord.DisplayName <> '',
|
||
aRecord.DisplayName, aRecord.Username));
|
||
|
||
firstWord := ExtractFirstWord(processedText);
|
||
if IsCommand(firstWord) then
|
||
begin
|
||
commandText := ExtractCommandText(processedText, firstWord);
|
||
responseText := ProcessCommand(firstWord);
|
||
decodeResponseSendToTTW(responseText, commandText, aRecord.DisplayName);
|
||
end;
|
||
TThread.Queue(nil,
|
||
procedure
|
||
begin
|
||
frOBS1.MsgToWebServer(aRecord);
|
||
end);
|
||
PlayNotifySound((aRecord.Moder = 1), (aRecord.Vip = 1),
|
||
(aRecord.Subscriber = 1));
|
||
processedText := StringReplace(processedText, '!', '', [rfReplaceAll]);
|
||
checkAndSendToGames(aRecord.DisplayName, processedText);
|
||
end;
|
||
|
||
procedure TTTW_Bot.PlayNotifySound(aMod, aVip, aSub: Boolean);
|
||
var
|
||
s: string;
|
||
sm: TSongMachine;
|
||
begin
|
||
|
||
sm := TSongMachine.Create;
|
||
try
|
||
if (aMod) and (frNotify1.chEnNotifyMod.IsChecked) and
|
||
(frNotify1.edtNotifyFileNameMod.text <> '') then
|
||
begin
|
||
if frNotify1.cbNotifyFileAgain1.IsChecked then
|
||
s := frNotify1.edtNotifyFileName.text
|
||
else
|
||
s := frNotify1.edtNotifyFileNameMod.text;
|
||
|
||
sm.PlaySilent(s, inttostr(round(frNotify1.tbNotifyVolumeMod.Value)));
|
||
exit;
|
||
end;
|
||
if (aVip) and (frNotify1.chEnNotifyVip.IsChecked) and
|
||
(frNotify1.edtNotifyFileNameVip.text <> '') then
|
||
begin
|
||
if frNotify1.cbNotifyFileAgain2.IsChecked then
|
||
s := frNotify1.edtNotifyFileName.text
|
||
else
|
||
s := frNotify1.edtNotifyFileNameVip.text;
|
||
sm.PlaySilent(s, inttostr(round(frNotify1.tbNotifyVolumeVip.Value)));
|
||
exit;
|
||
end;
|
||
if (aSub) and (frNotify1.chEnNotifySub.IsChecked) and
|
||
(frNotify1.edtNotifyFileNameSub.text <> '') then
|
||
begin
|
||
if frNotify1.cbNotifyFileAgain3.IsChecked then
|
||
s := frNotify1.edtNotifyFileName.text
|
||
else
|
||
s := frNotify1.edtNotifyFileNameSub.text;
|
||
sm.PlaySilent(s, inttostr(round(frNotify1.tbNotifyVolumeSub.Value)));
|
||
exit;
|
||
end;
|
||
if (frNotify1.chEnNotify.IsChecked) and
|
||
(frNotify1.edtNotifyFileName.text <> '') then
|
||
begin
|
||
s := frNotify1.edtNotifyFileName.text;
|
||
sm.PlaySilent(s, inttostr(round(frNotify1.tbNotifyVolume.Value)));
|
||
exit;
|
||
end;
|
||
finally
|
||
sm.Free;
|
||
end;
|
||
end;
|
||
|
||
procedure TTTW_Bot.frAutoActions1btnCounterAddClick(Sender: TObject);
|
||
var
|
||
I: Integer;
|
||
begin
|
||
frAutoActions1.btnCounterAddClick(Sender);
|
||
frCommands1.frContruct1.cbCounterName.Items.Clear;
|
||
for I := 0 to high(frAutoActions1.listCounters) do
|
||
frCommands1.frContruct1.cbCounterName.Items.Add
|
||
(frAutoActions1.listCounters[I].counterName);
|
||
end;
|
||
|
||
procedure TTTW_Bot.frAutoActions1btnCounterDeleteClick(Sender: TObject);
|
||
var
|
||
I: Integer;
|
||
begin
|
||
frAutoActions1.btnCounterDeleteClick(Sender);
|
||
frCommands1.frContruct1.cbCounterName.Items.Clear;
|
||
for I := 0 to high(frAutoActions1.listCounters) do
|
||
frCommands1.frContruct1.cbCounterName.Items.Add
|
||
(frAutoActions1.listCounters[I].counterName);
|
||
end;
|
||
|
||
procedure TTTW_Bot.frAutoActions1btnCounterEditClick(Sender: TObject);
|
||
var
|
||
I: Integer;
|
||
begin
|
||
frAutoActions1.btnCounterEditClick(Sender);
|
||
frCommands1.frContruct1.cbCounterName.Items.Clear;
|
||
for I := 0 to high(frAutoActions1.listCounters) do
|
||
frCommands1.frContruct1.cbCounterName.Items.Add
|
||
(frAutoActions1.listCounters[I].counterName);
|
||
end;
|
||
|
||
procedure TTTW_Bot.frCommands1btnRandAddClick(Sender: TObject);
|
||
begin
|
||
frCommands1.btnRandAddClick(Sender);
|
||
|
||
end;
|
||
|
||
procedure TTTW_Bot.frOBS1btnDeleteeChatClick(Sender: TObject);
|
||
begin
|
||
frOBS1.btnDeleteeChatClick(Sender);
|
||
|
||
end;
|
||
|
||
procedure TTTW_Bot.frSettings1btnDAStartClick(Sender: TObject);
|
||
begin
|
||
frSettings1.btnDAStartClick(Sender);
|
||
|
||
end;
|
||
|
||
procedure TTTW_Bot.frTTS1btnSendClick(Sender: TObject);
|
||
begin
|
||
frTTS1.btnSendClick(Sender);
|
||
|
||
end;
|
||
|
||
procedure TTTW_Bot.ReadDB;
|
||
|
||
function XorDecryptToStrings(const InputFile, Key: string): TStrings;
|
||
var
|
||
InStream: TFileStream;
|
||
MemStream: TMemoryStream;
|
||
KeyBytes: TBytes;
|
||
KeyLen, KeyIndex: Integer;
|
||
B: Byte;
|
||
begin
|
||
KeyBytes := TEncoding.ANSI.GetBytes(Key);
|
||
KeyLen := Length(KeyBytes);
|
||
if KeyLen = 0 then
|
||
raise Exception.Create('Ключ не может быть пустым');
|
||
|
||
InStream := TFileStream.Create(InputFile, fmOpenRead);
|
||
try
|
||
MemStream := TMemoryStream.Create;
|
||
try
|
||
KeyIndex := 0;
|
||
while InStream.Position < InStream.Size do
|
||
begin
|
||
InStream.ReadBuffer(B, 1);
|
||
B := B xor KeyBytes[KeyIndex];
|
||
MemStream.WriteBuffer(B, 1);
|
||
KeyIndex := (KeyIndex + 1) mod KeyLen;
|
||
end;
|
||
MemStream.Position := 0;
|
||
Result := TStringList.Create;
|
||
try
|
||
Result.LoadFromStream(MemStream, TEncoding.ANSI);
|
||
except
|
||
Result.Free; // Освобождаем при ошибке загрузки
|
||
raise;
|
||
end;
|
||
finally
|
||
MemStream.Free;
|
||
end;
|
||
finally
|
||
InStream.Free;
|
||
end;
|
||
end;
|
||
// Загрузка компонентов настроек (TEdit, TCheckBox)
|
||
procedure LoadSettingsComponents;
|
||
var
|
||
I: Integer;
|
||
c: TComponent;
|
||
begin
|
||
for I := 0 to frSettings1.ComponentCount - 1 do
|
||
begin
|
||
c := frSettings1.Components[I];
|
||
if c is TEdit then
|
||
TEdit(c).text := db.ReadSetting(TEdit(c).Name)
|
||
else if c is TCheckBox then
|
||
TCheckBox(c).IsChecked := (db.ReadSetting(TCheckBox(c).Name) = 'True');
|
||
end;
|
||
db.FChannel := frSettings1.edtChannel.text;
|
||
end;
|
||
|
||
// Загрузка данных в гриды команд
|
||
procedure LoadGridsData;
|
||
begin
|
||
db.LoadRecordArray<TRandomCounters>('RandomCounters',
|
||
frCommands1.RandomCounters);
|
||
db.LoadRecordArray<TListCommands>('listSounds', frCommands1.listSounds);
|
||
db.LoadRecordArray<TListCommands>('listFiles', frCommands1.listFiles);
|
||
db.LoadRecordArray<TListCommands>('listNeiro', frCommands1.listNeiro);
|
||
db.LoadRecordArray<TListCommands>('listCommands', frCommands1.listCommands);
|
||
frCommands1.UpdateGridFromArray;
|
||
|
||
end;
|
||
|
||
// Загрузка списка групп
|
||
procedure LoadGroupNames;
|
||
begin
|
||
db.getGroupName(frCommands1.frGroupsRequest1.lbRandomGroup.Items);
|
||
end;
|
||
|
||
// Загрузка зашифрованного конфига
|
||
procedure LoadEncryptedConfig;
|
||
var
|
||
tempList: TStrings; // Временный список для результата
|
||
I: Integer;
|
||
begin
|
||
if not FileExists(myConst.cfg1) then
|
||
exit;
|
||
|
||
tempList := nil; // Инициализация
|
||
try
|
||
tempList := XorDecryptToStrings(myConst.cfg1, 'fgvasrgEFAXFAFAS');
|
||
|
||
for I := 0 to tempList.Count - 1 do
|
||
begin
|
||
var
|
||
eqPos := Pos('=', tempList[I]);
|
||
if eqPos > 0 then
|
||
begin
|
||
var
|
||
Key := Trim(Copy(tempList[I], 1, eqPos - 1));
|
||
var
|
||
Value := Trim(Copy(tempList[I], eqPos + 1, MaxInt));
|
||
|
||
if Key = 'k1' then
|
||
appconst.TTV_ClientID := Value
|
||
else if Key = 'k2' then
|
||
appconst.AI_GigaChat_AC := Value
|
||
else if Key = 'k3' then
|
||
appconst.AI_GigaChat_ClientID := Value
|
||
else if Key = 'k4' then
|
||
appconst.AI_ChatGPT_Token := Value
|
||
else if Key = 'k5' then
|
||
appconst.AI_DeepSeec_Token := Value
|
||
else if Key = 'k6' then
|
||
appconst.DA_ClientID := Value
|
||
else if Key = 'k7' then
|
||
appconst.DA_Sicret := Value
|
||
else if Key = 'k8' then
|
||
appconst.DA_URL := Value;
|
||
end;
|
||
end;
|
||
|
||
frSettings1.btnGetClientID.Visible := (appconst.TTV_ClientID <> '');
|
||
frAI1.btnGetAIDef.Visible := ((appconst.AI_GigaChat_AC <> '') and
|
||
(appconst.AI_GigaChat_ClientID <> '')) or
|
||
(appconst.AI_ChatGPT_Token <> '') or (appconst.AI_DeepSeec_Token <> '');
|
||
frSettings1.btnGetDADef.Visible := (appconst.DA_ClientID <> '') and
|
||
(appconst.DA_Sicret <> '') and (appconst.DA_URL <> '');
|
||
finally
|
||
tempList.Free; // Важно: освобождаем временный список!
|
||
end;
|
||
end;
|
||
// Загрузка настроек уведомлений
|
||
procedure LoadNotifySettings;
|
||
var
|
||
I: Integer;
|
||
c: TComponent;
|
||
begin
|
||
for I := 0 to frNotify1.ComponentCount - 1 do
|
||
begin
|
||
c := frNotify1.Components[I];
|
||
if c is TEdit then
|
||
TEdit(c).text := db.ReadSetting(TEdit(c).Name)
|
||
else if c is TCheckBox then
|
||
TCheckBox(c).IsChecked := (db.ReadSetting(TCheckBox(c).Name) = 'True')
|
||
else if c is TSwitch then
|
||
TSwitch(c).IsChecked := (db.ReadSetting(TSwitch(c).Name) = 'True')
|
||
else if c is TTrackBar then
|
||
TTrackBar(c).Value :=
|
||
strtoint(db.ReadSetting(TTrackBar(c).Name, '100'));
|
||
end;
|
||
end;
|
||
|
||
// Загрузка настроек ИИ
|
||
procedure LoadAISettings;
|
||
var
|
||
I: Integer;
|
||
c: TComponent;
|
||
ii: Integer;
|
||
|
||
// Настройки GigaChat
|
||
procedure SetupGigaChatSettings;
|
||
begin
|
||
frAI1.rbGC.IsChecked := true;
|
||
frAI1.Label45.text := 'ClientID';
|
||
frAI1.Label47.text := 'Autorization Code';
|
||
frAI1.Label1.Visible := false;
|
||
frAI1.edtAIP2.Visible := true;
|
||
frAI1.edtAIP2.Password := true;
|
||
frAI1.edtAIP3.Visible := false;
|
||
frAI1.cbOllama.Visible := false;
|
||
end;
|
||
|
||
// Настройки DeepSeek
|
||
procedure SetupDeepSeekSettings;
|
||
begin
|
||
frAI1.rbDS.IsChecked := true;
|
||
frAI1.Label45.text := 'API Token';
|
||
frAI1.Label47.text := '';
|
||
frAI1.Label1.Visible := false;
|
||
frAI1.edtAIP2.Visible := false;
|
||
frAI1.edtAIP3.Visible := false;
|
||
frAI1.cbOllama.Visible := false;
|
||
end;
|
||
|
||
// Настройки ChatGPT
|
||
procedure SetupChatGPTSettings;
|
||
begin
|
||
frAI1.rbCG.IsChecked := true;
|
||
frAI1.Label45.text := 'API Token';
|
||
frAI1.Label47.text := '';
|
||
frAI1.Label1.Visible := false;
|
||
frAI1.edtAIP2.Visible := false;
|
||
frAI1.edtAIP3.Visible := false;
|
||
frAI1.cbOllama.Visible := false;
|
||
end;
|
||
|
||
// Настройки кастомного ИИ
|
||
procedure SetupCustomAISettings;
|
||
begin
|
||
frAI1.RBCustom.IsChecked := true;
|
||
frAI1.Label45.text := 'API Token';
|
||
frAI1.Label47.text := 'URL';
|
||
frAI1.Label1.Visible := true;
|
||
frAI1.edtAIP2.Visible := true;
|
||
frAI1.edtAIP2.Password := false;
|
||
frAI1.edtAIP3.Visible := true;
|
||
frAI1.cbOllama.Visible := true;
|
||
frAI1.cbOllama.IsChecked := db.ReadSetting(frAI1.cbOllama.Name) = '1';
|
||
end;
|
||
|
||
begin
|
||
for I := 0 to frAI1.ComponentCount - 1 do
|
||
begin
|
||
c := frAI1.Components[I];
|
||
if c is TEdit then
|
||
TEdit(c).text := db.ReadSetting(TEdit(c).Name)
|
||
else if c is TCheckBox then
|
||
TCheckBox(c).IsChecked := db.ReadSetting(TCheckBox(c).Name) = '1';
|
||
end;
|
||
|
||
ii := strtoint(db.ReadSetting('aiIndex', '0'));
|
||
case ii of
|
||
0:
|
||
SetupGigaChatSettings;
|
||
1:
|
||
SetupDeepSeekSettings;
|
||
2:
|
||
SetupChatGPTSettings;
|
||
3:
|
||
SetupCustomAISettings;
|
||
end;
|
||
|
||
frSettings1.Init;
|
||
|
||
end;
|
||
|
||
// Загрузка гридов автоматических действий
|
||
procedure LoadAutoActionsGrids;
|
||
var
|
||
I: Integer;
|
||
begin
|
||
db.LoadRecordArray<TListTimer>('listTimer', frAutoActions1.listTimer);
|
||
db.LoadRecordArray<TBanWord>('listBanWords', frAutoActions1.listBanWords);
|
||
db.LoadRecordArray<TCounter>('listCounters', frAutoActions1.listCounters);
|
||
for I := 0 to High(frAutoActions1.listCounters) do
|
||
frCommands1.frContruct1.cbCounterName.Items.Add
|
||
(frAutoActions1.listCounters[I].counterName);
|
||
frCommands1.frContruct1.cbTextToSpeach.IsChecked :=
|
||
db.ReadSetting('cbTextToSpeach', 'False') = 'True';
|
||
frCommands1.frContruct1.cbHelloTTS.IsChecked :=
|
||
db.ReadSetting('cbHelloTTS', 'False') = 'True';
|
||
frAutoActions1.initTimers;
|
||
frAutoActions1.UpdateGridFromArray;
|
||
end;
|
||
|
||
// Загрузка интеграций с ОБС
|
||
procedure LoadOBSGrids;
|
||
var
|
||
I: Integer;
|
||
begin
|
||
db.LoadRecordArray<TOBSChat>('listChats', frOBS1.listChats);
|
||
|
||
frOBS1.BTTV := TBTTV.Create;
|
||
frOBS1.m7tv := t7tv.Create;
|
||
frOBS1.ChatBadges := TList<TChatBadge>.Create;
|
||
frOBS1.ChatEmotes := TList<TEmotes>.Create;
|
||
frOBS1.ChatWebServers := TList<TChatWebServers>.Create;
|
||
|
||
for I := 0 to High(frOBS1.listChats) do
|
||
begin
|
||
frOBS1.CreateWebChat(frOBS1.listChats[I]);
|
||
end;
|
||
|
||
db.LoadRecordArray<TOBSNotify>('listNotify', frOBS1.listNotify);
|
||
frOBS1.EventWebServers := TList<TEventWebServers>.Create;
|
||
for I := 0 to High(frOBS1.listNotify) do
|
||
begin
|
||
|
||
frOBS1.CreateWebEvents(frOBS1.listNotify[I]);
|
||
end;
|
||
db.LoadRecordArray<TOBSKandinsky>('listKandinsky', frOBS1.listKandinsky);
|
||
frOBS1.KandinskyWebServers := TList<TKandinskyWebServers>.Create;
|
||
if (frAI1.edtKandiKey.text <> '') and (frAI1.edtKandiSecret.text <> '') then
|
||
begin
|
||
for I := 0 to High(frOBS1.listKandinsky) do
|
||
begin
|
||
frOBS1.CreateWebKandinsky(frOBS1.listKandinsky[I]);
|
||
end;
|
||
|
||
end;
|
||
|
||
db.LoadRecordArray<TOBSGames>('listGames', frOBS1.listGames);
|
||
frOBS1.GameWebServers := TList<TGameWebServers>.Create;
|
||
for I := 0 to High(frOBS1.listGames) do
|
||
begin
|
||
frOBS1.CreateWebGame(frOBS1.listGames[I].game, frOBS1.listGames[I].port);
|
||
end;
|
||
|
||
frOBS1.UpdateGridFromArray;
|
||
end;
|
||
|
||
// Загрузка навыков
|
||
procedure LoadSkills;
|
||
begin
|
||
db.LoadRecordArray<TEventGlobal>('ListEvents', frEvents1.ListEvents);
|
||
frEvents1.UpdateGrid;
|
||
frRevards1.CustomRewards := TList<TCustomRevards>.Create;
|
||
|
||
frEvents1.CustomRewardEvents := TList<TCustomRewardEvent>.Create;
|
||
kePoints := TKE.Create(frEvents1.edtParams, frEvents1.cbKey1,
|
||
frEvents1.cbKey2, frEvents1.cbKey3);
|
||
frTTS1.btnUpdateVoicesClick(Self);
|
||
frTTS1.cbVoices.ItemIndex := strtoint(db.ReadSetting('cbVoices', '0'));
|
||
frTTS1.cbOutput.ItemIndex := strtoint(db.ReadSetting('cbOutput', '0'));
|
||
|
||
end;
|
||
|
||
begin
|
||
LoadAISettings;
|
||
LoadSkills;
|
||
LoadSettingsComponents;
|
||
LoadGridsData;
|
||
LoadGroupNames;
|
||
LoadEncryptedConfig;
|
||
|
||
LoadNotifySettings;
|
||
|
||
LoadOBSGrids;
|
||
LoadAutoActionsGrids;
|
||
end;
|
||
|
||
procedure TTTW_Bot.SpeedButton1Click(Sender: TObject);
|
||
begin
|
||
ShellExecute(0, 'open', pwidechar('https://www.twitch.tv/incadence'),
|
||
nil, nil, 1);
|
||
end;
|
||
|
||
procedure TTTW_Bot.SpeedButton2Click(Sender: TObject);
|
||
begin
|
||
// https://www.twitch.tv/kuznecogr
|
||
ShellExecute(0, 'open', pwidechar('https://www.twitch.tv/kuznecogr'),
|
||
nil, nil, 1);
|
||
end;
|
||
|
||
procedure TTTW_Bot.SpeedButton3Click(Sender: TObject);
|
||
begin
|
||
// https://www.flaticon.com/ru/authors/karacis
|
||
ShellExecute(0, 'open',
|
||
pwidechar('https://www.flaticon.com/ru/authors/karacis'), nil, nil, 1);
|
||
end;
|
||
|
||
procedure TTTW_Bot.toLog(aModule, aMethod, aMessage: string; aCode: Integer);
|
||
begin
|
||
TThread.Synchronize(nil,
|
||
procedure
|
||
var
|
||
ml: TRLog;
|
||
begin
|
||
// Инициализация всех полей записи
|
||
ml.rTime := Now;
|
||
case aCode of
|
||
0:
|
||
ml.rType := 'INFO';
|
||
1:
|
||
ml.rType := 'WARNING';
|
||
2:
|
||
ml.rType := 'ERROR';
|
||
3:
|
||
ml.rType := 'DEBUG';
|
||
else
|
||
ml.rType := 'UNKNOWN';
|
||
end;
|
||
ml.rModule := aModule; // string
|
||
ml.rMethod := aMethod; // string
|
||
ml.rMessage := aMessage; // string
|
||
// Добавляем запись в список
|
||
frLog1.FLogList.Add(ml);
|
||
// Обновляем грид
|
||
frLog1.UpdateGridFilters;
|
||
end);
|
||
end;
|
||
|
||
procedure TTTW_Bot.decodeResponseSendToTTW(aResponseText, aCommandText,
|
||
adName: string);
|
||
var
|
||
res: string;
|
||
|
||
ID: string;
|
||
RowIndex: Integer;
|
||
begin
|
||
|
||
res := '';
|
||
res := aResponseText;
|
||
RowIndex := FindUserRow(adName);
|
||
ID := userlist[RowIndex].ID;
|
||
if ID = '' then
|
||
ID := '0';
|
||
// ----------------------------------------Группы ответов
|
||
res := ResponsParserGroups(res);
|
||
// ----------------------------------------рандомы
|
||
res := ResponsParserRandoms(res);
|
||
// ----------------------------------------счетчики
|
||
res := ResponsParserCounters(res);
|
||
// ----------------------------------------константы
|
||
res := ResponsParserStatic(res, adName, aCommandText);
|
||
// ----------------------------------------апи команды
|
||
res := ResponsParserAPI(res, adName);
|
||
// ----------------------------------------GPT
|
||
res := ResponsParserGPT(res, aCommandText);
|
||
// ----------------------------------------звуки
|
||
res := ResponsParserSounds(res);
|
||
// ----------------------------------------text
|
||
res := ResponsParserText(res);
|
||
// ----------------------------------------AIGen
|
||
res := ResponsParserAIGen(res, aCommandText);
|
||
// ----------------------------------------AIPic
|
||
res := ResponsParserAIPic(res, aCommandText, adName);
|
||
if res <> '' then
|
||
ttw_IRS.sendMessage(res);
|
||
end;
|
||
|
||
function TTTW_Bot.Pars(T_, text, _T: string): string;
|
||
var
|
||
A, B: Integer;
|
||
begin
|
||
Result := '';
|
||
A := Pos(T_, text);
|
||
if A = 0 then
|
||
exit;
|
||
A := A + Length(T_);
|
||
B := Pos(_T, text, A);
|
||
if B > 0 then
|
||
Result := Copy(text, A, B - A);
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserGroups(inMess: string): string;
|
||
var
|
||
ss, ss2, res: string;
|
||
|
||
sl: TStringList;
|
||
begin
|
||
res := inMess;
|
||
while Pos('{{', res) <> 0 do
|
||
begin
|
||
ss := Pars('{{', res, '}}');
|
||
sl := TStringList.Create;
|
||
randomize;
|
||
db.getGroupResponse(ss, sl);
|
||
ss2 := sl[random(sl.Count)];
|
||
res := StringReplace(res, '{{' + ss + '}}', ss2, [rfReplaceAll]);
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserSounds(inMess: string): string;
|
||
var
|
||
ss, res: string;
|
||
I, p: Integer;
|
||
sm: TSongMachine;
|
||
begin
|
||
res := inMess;
|
||
sm := TSongMachine.Create;
|
||
try
|
||
if ContainsText(res, '||') then
|
||
begin
|
||
// Находим позицию первого '||'
|
||
p := Pos('||', res);
|
||
// Копируем все, что идет после первого '||'
|
||
ss := Copy(res, p + 2, Length(res) - p - 1);
|
||
// +2 чтобы пропустить первый '||'
|
||
// Находим позицию второго '||'
|
||
p := Pos('||', ss);
|
||
if p > 0 then
|
||
begin
|
||
// Копируем текст между '||'
|
||
ss := Copy(ss, 1, p - 1);
|
||
if ss <> '' then
|
||
begin
|
||
// Ищем значение в sgSAFiles
|
||
for I := 0 to high(frCommands1.listSounds) do
|
||
begin
|
||
if frCommands1.listSounds[I].R1 = ss then
|
||
begin
|
||
if FileExists(frCommands1.listSounds[I].R2) then
|
||
begin
|
||
{ PlaySong(sgSAFiles.Cells[1, i],
|
||
inttostr(round(tbSoundVolume.Value)), True); }
|
||
sm.PlayPublic(frCommands1.listSounds[I].R2,
|
||
inttostr(round(100)));
|
||
end
|
||
else
|
||
begin
|
||
toLog('uGeneral', 'ResponsParserSounds',
|
||
'Файл "' + frCommands1.listSounds[I].R1 + '" не найден: ' +
|
||
frCommands1.listSounds[I].R2, 2);
|
||
end;
|
||
Break;
|
||
end;
|
||
end;
|
||
// Удаляем обработанный фрагмент из исходной строки
|
||
res := StringReplace(res, '||' + ss + '||', '', [rfReplaceAll]);
|
||
end;
|
||
end;
|
||
end;
|
||
finally
|
||
sm.Free;
|
||
end;
|
||
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserText(inMess: string): string;
|
||
var
|
||
ss, res, fn, rres: string;
|
||
sll: TStringList;
|
||
I, p: Integer;
|
||
begin
|
||
res := inMess;
|
||
if ContainsText(res, '|(') then
|
||
begin
|
||
p := Pos('|(', res);
|
||
ss := Copy(res, p, Length(res) - p);
|
||
p := Pos('|(', ss, 2);
|
||
ss := Copy(ss, 1, p + 1);
|
||
ss := StringReplace(ss, '|(', '', [rfReplaceAll]);
|
||
if ss <> '' then
|
||
begin
|
||
for I := 0 to high(frCommands1.listFiles) do
|
||
begin
|
||
if frCommands1.listFiles[I].R1 = ss then
|
||
begin
|
||
fn := frCommands1.listFiles[I].R2;
|
||
Break;
|
||
end;
|
||
end;
|
||
sll := TStringList.Create;
|
||
try
|
||
sll.LoadFromFile(fn, TEncoding.UTF8);
|
||
rres := sll.text;
|
||
finally
|
||
sll.Free;
|
||
end;
|
||
if rres <> '' then
|
||
begin
|
||
if Length(rres) > 450 then
|
||
begin
|
||
rres := Copy(rres, 1, 450);
|
||
rres := rres + '...';
|
||
end;
|
||
rres := StringReplace(rres, #13#10, ' ', [rfReplaceAll]);
|
||
res := StringReplace(res, '|(' + ss + '|(', rres, [rfReplaceAll]);
|
||
end;
|
||
end;
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserRandoms(inMess: string): string;
|
||
var
|
||
r, res: string;
|
||
I: Integer;
|
||
|
||
function RandomInRange(MinValue, MaxValue: Integer): Integer;
|
||
begin
|
||
randomize;
|
||
Result := random(MaxValue - MinValue + 1) + MinValue;
|
||
end;
|
||
|
||
begin
|
||
res := inMess;
|
||
while ContainsText(res, '[[') do
|
||
begin
|
||
r := Pars('[[', res, ']]');
|
||
for I := 0 to high(frCommands1.RandomCounters) do
|
||
begin
|
||
if frCommands1.RandomCounters[I].rndName = r then
|
||
begin
|
||
res := StringReplace(res, '[[' + r + ']]',
|
||
inttostr(RandomInRange(frCommands1.RandomCounters[I].Ot,
|
||
frCommands1.RandomCounters[I].ToValue)), [rfReplaceAll]);
|
||
Break;
|
||
end;
|
||
end;
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserCounters(inMess: string): string;
|
||
var
|
||
r, res: string;
|
||
I: Integer;
|
||
begin
|
||
res := inMess;
|
||
while ContainsText(res, '``') do
|
||
begin
|
||
r := Pars('``', res, '``');
|
||
for I := 0 to high(frAutoActions1.listCounters) do
|
||
begin
|
||
if frAutoActions1.listCounters[I].counterName = r then
|
||
begin
|
||
res := StringReplace(res, '``' + r + '``',
|
||
inttostr(frAutoActions1.listCounters[I].Count), [rfReplaceAll]);
|
||
Break;
|
||
end;
|
||
end;
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserStatic(inMess, adName,
|
||
aCommandText: string): string;
|
||
var
|
||
res, RandomUserName: string;
|
||
begin
|
||
res := inMess;
|
||
res := StringReplace(res, '[USERNAME]', '@' + adName, [rfReplaceAll]);
|
||
res := StringReplace(res, '[TO]', aCommandText, [rfReplaceAll]);
|
||
if ContainsText(res, '[RANDOMUSER]') then
|
||
begin
|
||
if Pos('@', aCommandText) <> 0 then
|
||
begin
|
||
RandomUserName := aCommandText;
|
||
end
|
||
else
|
||
begin
|
||
randomize;
|
||
RandomUserName := '@' + userlist[random(userlist.Count)].login;
|
||
end;
|
||
res := StringReplace(res, '[RANDOMUSER]', RandomUserName, [rfReplaceAll]);
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
procedure TTTW_Bot.gptError(Msg: string);
|
||
begin
|
||
toLog('GPT', 'gptError', Msg, 2);
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserAIGen(inMess, aCommandText: string): string;
|
||
var
|
||
res, GPTRequest: string;
|
||
GigaChat: TGigaChat;
|
||
ChatAPI: TChatAPI;
|
||
mystr: string;
|
||
p, I: Integer;
|
||
ss: string;
|
||
begin
|
||
res := inMess;
|
||
if ContainsText(res, '<|') then
|
||
begin
|
||
// Находим позицию первого '||'
|
||
p := Pos('<|', res);
|
||
// Копируем все, что идет после первого '<|'
|
||
ss := Copy(res, p + 2, Length(res) - p - 1);
|
||
// +2 чтобы пропустить первый '<|'
|
||
// Находим позицию второго '<|'
|
||
p := Pos('<|', ss);
|
||
if p > 0 then
|
||
begin
|
||
// Копируем текст между '<|'
|
||
ss := Copy(ss, 1, p - 1);
|
||
if ss <> '' then
|
||
begin
|
||
// Ищем значение в sgSAFiles
|
||
for I := 0 to high(frCommands1.listNeiro) do
|
||
begin
|
||
if frCommands1.listNeiro[I].R1 = ss then
|
||
begin
|
||
mystr := frCommands1.listNeiro[I].R2;
|
||
Break;
|
||
end;
|
||
end;
|
||
// Удаляем обработанный фрагмент из исходной строки
|
||
// res := StringReplace(res, '<|' + ss + '<|', mystr, [rfReplaceAll]);
|
||
end;
|
||
end;
|
||
end;
|
||
mystr := StringReplace(mystr, '[UT]', aCommandText, [rfReplaceAll]);
|
||
|
||
mystr := StringReplace(mystr, '[AI]', '', [rfReplaceAll]);
|
||
if (frAI1.edtAIP1.text = '') then
|
||
begin
|
||
GPTRequest :=
|
||
'тут должен быть ответ нейросети, но стример зажал логиниться';
|
||
end
|
||
else
|
||
begin
|
||
if frAI1.rbGC.IsChecked then // GigaChat
|
||
begin
|
||
GigaChat := TGigaChat.Create(Self, frAI1.edtAIP1.text, frAI1.edtAIP2.text,
|
||
frAI1.edtGPTPrefix.text);
|
||
try
|
||
try
|
||
GPTRequest := GigaChat.GetGPTRequest
|
||
('https://gigachat.devices.sberbank.ru/api/v1/chat/completions',
|
||
'GigaChat', mystr);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserAIGen.gigachat', E.Message, 2);
|
||
end;
|
||
finally
|
||
GigaChat.Destroy;
|
||
end;
|
||
end;
|
||
if frAI1.rbDS.IsChecked then // DeepSeek
|
||
begin
|
||
ChatAPI := TChatAPI.Create(Self, frAI1.edtAIP1.text,
|
||
frAI1.edtGPTPrefix.text);
|
||
try
|
||
ChatAPI.OnError := gptError;
|
||
try
|
||
GPTRequest := ChatAPI.GetGPTRequest
|
||
('https://api.deepseek.com/chat/completions',
|
||
'deepseek-chat', mystr);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserAIGen.deepseek', E.Message, 2);
|
||
end;
|
||
finally
|
||
ChatAPI.Destroy;
|
||
end;
|
||
end;
|
||
if frAI1.rbCG.IsChecked then // ChatGPT
|
||
begin
|
||
ChatAPI := TChatAPI.Create(Self, frAI1.edtAIP1.text,
|
||
frAI1.edtGPTPrefix.text);
|
||
try
|
||
try
|
||
GPTRequest := ChatAPI.GetGPTRequest
|
||
('https://api.openai.com/v1/chat/completions',
|
||
'gpt-3.5-turbo', mystr);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserAIGen.openai', E.Message, 2);
|
||
end;
|
||
finally
|
||
ChatAPI.Destroy;
|
||
end;
|
||
end;
|
||
if frAI1.RBCustom.IsChecked then // Custom
|
||
begin
|
||
ChatAPI := TChatAPI.Create(Self, frAI1.edtAIP1.text,
|
||
frAI1.edtGPTPrefix.text);
|
||
try
|
||
try
|
||
GPTRequest := ChatAPI.GetGPTRequest(frAI1.edtAIP2.text,
|
||
frAI1.edtAIP3.text, mystr);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserAIGen.custom', E.Message, 2);
|
||
end;
|
||
finally
|
||
ChatAPI.Destroy;
|
||
end;
|
||
end;
|
||
|
||
GPTRequest := StringReplace(GPTRequest, 'nn', ' ', [rfReplaceAll]);
|
||
GPTRequest := StringReplace(GPTRequest, 'nn', ' ', [rfReplaceAll]);
|
||
if GPTRequest = '' then
|
||
GPTRequest := 'ой, кажется нейронка пока не доступна';
|
||
|
||
end;
|
||
res := StringReplace(res, '<|' + ss + '<|', GPTRequest, [rfReplaceAll]);
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserAIPic(inMess, aCommandText,
|
||
aNick: string): string;
|
||
var
|
||
res: string;
|
||
I: Integer;
|
||
begin
|
||
res := inMess;
|
||
if ContainsText(res, '[Kandinsky]') then
|
||
begin
|
||
for I := 0 to frOBS1.KandinskyWebServers.Count - 1 do
|
||
frOBS1.KandinskyWebServers[I].WebServerKandinsky.generate
|
||
(aCommandText, aNick);
|
||
res := StringReplace(res, '[Kandinsky]', '', [rfReplaceAll]);
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserAPI(inMess, adName: string): string;
|
||
var
|
||
res, follow, age, ID: string;
|
||
RowIndex: Integer;
|
||
u: TUser;
|
||
function GetPeriodEnding(n, r: Integer): string;
|
||
var
|
||
res: array [0 .. 3, 0 .. 2] of string;
|
||
begin
|
||
res[0, 0] := 'год';
|
||
res[0, 1] := 'года';
|
||
res[0, 2] := 'лет';
|
||
|
||
res[1, 0] := 'месяц';
|
||
res[1, 1] := 'месяца';
|
||
res[1, 2] := 'месяцев';
|
||
|
||
res[2, 0] := 'день';
|
||
res[2, 1] := 'дня';
|
||
res[2, 2] := 'дней';
|
||
|
||
res[3, 0] := 'раз';
|
||
res[3, 1] := 'раза';
|
||
res[3, 2] := 'раз';
|
||
|
||
if (n mod 10 = 1) and (n mod 100 <> 11) then
|
||
Result := res[r, 0]
|
||
else if (n mod 10 >= 2) and (n mod 10 <= 4) and
|
||
((n mod 100 < 10) or (n mod 100 >= 20)) then
|
||
Result := res[r, 1]
|
||
else
|
||
Result := res[r, 2];
|
||
end;
|
||
function GetDateDifference(const inputDate: string): string;
|
||
var
|
||
currentDate, targetDate: TDateTime;
|
||
years, months, days: Integer;
|
||
begin
|
||
try
|
||
targetDate := StrToDate(inputDate);
|
||
currentDate := Now;
|
||
|
||
years := YearsBetween(currentDate, targetDate);
|
||
targetDate := IncYear(targetDate, years);
|
||
|
||
months := MonthsBetween(currentDate, targetDate);
|
||
targetDate := IncMonth(targetDate, months);
|
||
|
||
days := DaysBetween(currentDate, targetDate);
|
||
|
||
Result := inttostr(years) + ' ' + GetPeriodEnding(years, 0) + ' ' +
|
||
inttostr(months) + ' ' + GetPeriodEnding(months, 1) + ' ' +
|
||
inttostr(days) + ' ' + GetPeriodEnding(days, 2);
|
||
except
|
||
on E: Exception do
|
||
begin
|
||
toLog('uGeneral', 'ResponsParserAPI.GetDateDifference', E.Message, 2);
|
||
Result := '';
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
begin
|
||
res := inMess;
|
||
RowIndex := FindUserRow(adName);
|
||
u := userlist[RowIndex];
|
||
ID := u.ID;
|
||
if ContainsText(res, '[FOLLOW]') then
|
||
begin
|
||
if YearOf(u.follow_at) < 2000 then
|
||
u.follow_at := ttw_API.getFollow(ID);
|
||
follow := GetDateDifference(DateToStr(u.follow_at));
|
||
res := StringReplace(res, '[FOLLOW]', follow, [rfReplaceAll]);
|
||
end;
|
||
if ContainsText(res, '[AGE]') then
|
||
begin
|
||
if YearOf(userlist[RowIndex].created_at) < 2000 then
|
||
u := ttw_API.getUserbyLogin(u.login);
|
||
age := GetDateDifference(DateToStr(u.created_at));
|
||
res := StringReplace(res, '[AGE]', age, [rfReplaceAll]);
|
||
end;
|
||
userlist[RowIndex] := u;
|
||
if ContainsText(res, '[STAT]') then
|
||
begin
|
||
var
|
||
avg_viewers: Integer;
|
||
var
|
||
max_viewers: Integer;
|
||
var
|
||
hours_watched: Integer;
|
||
var
|
||
followers: Integer;
|
||
var
|
||
followers_total: Integer;
|
||
ttw_API.getTTWStat(db.FChannel, avg_viewers, max_viewers, hours_watched,
|
||
followers, followers_total);
|
||
var
|
||
resultStat: string;
|
||
resultStat := 'Статистика канала за месяц: Средний онлайн: ' +
|
||
inttostr(avg_viewers) + '; Максимальный онлайн: ' + inttostr(max_viewers)
|
||
+ '; Часов просмотра: ' + inttostr(hours_watched) +
|
||
'; Подписчиков за месяц: ' + inttostr(followers) + '; Всего подписчиков: '
|
||
+ inttostr(followers_total);
|
||
res := StringReplace(res, '[STAT]', resultStat, [rfReplaceAll]);
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
function TTTW_Bot.ResponsParserGPT(inMess, aCommandText: string): string;
|
||
var
|
||
res, GPTRequest: string;
|
||
GigaChat: TGigaChat;
|
||
ChatAPI: TChatAPI;
|
||
begin
|
||
res := inMess;
|
||
|
||
if ContainsText(res, '[AI]') then
|
||
begin
|
||
|
||
begin
|
||
if frAI1.rbGC.IsChecked then // GigaChat
|
||
begin
|
||
GigaChat := TGigaChat.Create(Self, frAI1.edtAIP1.text,
|
||
frAI1.edtAIP2.text, frAI1.edtGPTPrefix.text);
|
||
try
|
||
try
|
||
GPTRequest := GigaChat.GetGPTRequest
|
||
('https://gigachat.devices.sberbank.ru/api/v1/chat/completions',
|
||
'GigaChat', aCommandText);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserGPT.gigachat', E.Message, 2);
|
||
end;
|
||
finally
|
||
GigaChat.Destroy;
|
||
end;
|
||
end;
|
||
if frAI1.rbDS.IsChecked then // DeepSeek
|
||
begin
|
||
ChatAPI := TChatAPI.Create(Self, frAI1.edtAIP1.text,
|
||
frAI1.edtGPTPrefix.text);
|
||
try
|
||
ChatAPI.OnError := gptError;
|
||
try
|
||
GPTRequest := ChatAPI.GetGPTRequest
|
||
('https://api.deepseek.com/chat/completions', 'deepseek-chat',
|
||
aCommandText);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserGPT.deepseek', E.Message, 2);
|
||
end;
|
||
finally
|
||
ChatAPI.Destroy;
|
||
end;
|
||
end;
|
||
if frAI1.rbCG.IsChecked then // ChatGPT
|
||
begin
|
||
ChatAPI := TChatAPI.Create(Self, frAI1.edtAIP1.text,
|
||
frAI1.edtGPTPrefix.text);
|
||
try
|
||
try
|
||
GPTRequest := ChatAPI.GetGPTRequest
|
||
('https://api.openai.com/v1/chat/completions', 'gpt-3.5-turbo',
|
||
aCommandText);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserGPT.openai', E.Message, 2);
|
||
end;
|
||
finally
|
||
ChatAPI.Destroy;
|
||
end;
|
||
end;
|
||
if frAI1.RBCustom.IsChecked then // Custom
|
||
begin
|
||
ChatAPI := TChatAPI.Create(Self, frAI1.edtAIP1.text,
|
||
frAI1.edtGPTPrefix.text);
|
||
try
|
||
try
|
||
GPTRequest := ChatAPI.GetGPTRequest(frAI1.edtAIP2.text,
|
||
frAI1.edtAIP3.text, aCommandText, frAI1.cbOllama.IsChecked);
|
||
except
|
||
on E: Exception do
|
||
toLog('uGeneral', 'ResponsParserGPT.custom', E.Message, 2);
|
||
end;
|
||
finally
|
||
ChatAPI.Destroy;
|
||
end;
|
||
end;
|
||
|
||
GPTRequest := StringReplace(GPTRequest, 'nn', ' ', [rfReplaceAll]);
|
||
GPTRequest := StringReplace(GPTRequest, 'nn', ' ', [rfReplaceAll]);
|
||
if GPTRequest = '' then
|
||
GPTRequest := 'ой, кажется нейронка пока не доступна';
|
||
end;
|
||
res := StringReplace(res, '[AI]', GPTRequest, [rfReplaceAll]);
|
||
end;
|
||
Result := res;
|
||
end;
|
||
|
||
end.
|