407 lines
12 KiB
MQL5
407 lines
12 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| TlgReciber.mqh |
|
|
//| Copyright 2025, Niquel Mendoza. |
|
|
//| https://www.mql5.com/es/users/nique_372 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Niquel Mendoza."
|
|
#property link "https://www.mql5.com/es/users/nique_372"
|
|
#property strict
|
|
|
|
#ifndef AIFULLTAB_SRC_TLG_TLGRECIBER_MQH
|
|
#define AIFULLTAB_SRC_TLG_TLGRECIBER_MQH
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "Def.mqh"
|
|
#include "..\\..\\..\\TelegramByLeo\\Telegram.mqh"
|
|
#include <TSN\\MQLArticles\\Utils\\Basic.mqh>
|
|
#include <TSN\\LLM\\Main.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
namespace TSN
|
|
{
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CEasyTokCounter : public ILLmTokensCounter
|
|
{
|
|
public:
|
|
CEasyTokCounter(void) {}
|
|
~CEasyTokCounter(void) {}
|
|
int Count(const string& text) override final { return StringLen(text) >> 2; }// 4 aprox
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CChatTelegramBase : public CTlgFullBot
|
|
{
|
|
protected:
|
|
//---
|
|
bool m_init;
|
|
long m_chart_id_padre;
|
|
double m_key;
|
|
const long m_chart_id;
|
|
|
|
//---
|
|
CAgentBase* m_agent;
|
|
CLLmToolsManager* m_tools;
|
|
CEasyTokCounter m_tok;
|
|
|
|
//---
|
|
bool m_in_execution;
|
|
bool m_first;
|
|
|
|
|
|
//---
|
|
virtual bool OnBeforeSetTools() = 0;
|
|
|
|
public:
|
|
CChatTelegramBase();
|
|
~CChatTelegramBase(void);
|
|
|
|
//---
|
|
bool Init(const long chart_id_padre, double key,
|
|
const string& system_promt, const string& prompt_to_resume,
|
|
const string& db_folder, bool comon);
|
|
|
|
//---
|
|
void ProcessMessages() override final;
|
|
|
|
//---
|
|
void OnTimerEvent();
|
|
|
|
//---
|
|
void ChartEvent(const int32_t id, const long& lparam, const double& dparam, const string& sparam);
|
|
};
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CChatTelegramBase::CChatTelegramBase()
|
|
: m_chart_id_padre(-1), m_in_execution(false), m_init(false), m_key(-1.0), m_first(false),
|
|
m_chart_id(ChartID()), m_agent(NULL), m_tools(NULL)
|
|
{
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CChatTelegramBase::~CChatTelegramBase(void)
|
|
{
|
|
//---
|
|
if(CheckPointer(m_agent) == POINTER_DYNAMIC)
|
|
{
|
|
delete m_agent;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CChatTelegramBase::Init(const long chart_id_padre, double key,
|
|
const string& system_promt, const string& prompt_to_resume,
|
|
const string& db_folder, bool comon)
|
|
{
|
|
//---
|
|
if(m_init)
|
|
return true;
|
|
|
|
//-- Consutrccion inicial
|
|
m_agent = LlmAgentsByLeo_CreateGroqAgent();
|
|
m_tools = LlmAgentsByLeo_CreateGroqToolManager();
|
|
|
|
//---
|
|
m_agent.SetSystemPromt(system_promt);
|
|
m_agent.SetPromtResume(prompt_to_resume);
|
|
|
|
//---
|
|
m_agent.SetTools(m_tools);
|
|
m_agent.ToolsDeleteInDestructor(true);
|
|
m_agent.SetTokCounter(&m_tok);
|
|
m_agent.TokCounterDelInConstructor(false);
|
|
m_agent.GetParametersModel().Set("reasoning_format", "hidden", 0);
|
|
|
|
//---
|
|
if(!m_agent.OpenSqlDbModels(db_folder, comon))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
//--- parametros por defecto...
|
|
/* La idea e sque al inicar solo hagmaos lo basico luego el user antes de conectar telegram debera de configurar todo
|
|
m_agent.GetParametersModel().Set("model", "qwen/qwen3-32b", 0);
|
|
m_agent.GetParametersModel().Set("max_completion_tokens", long(1024));
|
|
*/
|
|
//---
|
|
m_chart_id_padre = chart_id_padre;
|
|
m_key = key;
|
|
m_tools.InitializeToolBuild();
|
|
|
|
//--- Cargar todas las tools con esquema y todo..
|
|
if(!OnBeforeSetTools())
|
|
return false;
|
|
|
|
//---
|
|
if(!m_tools.FinishToolBuild())
|
|
{
|
|
LogError("Fallo al finalizar build de json tools", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
m_init = true;
|
|
|
|
//---
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CChatTelegramBase::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
|
{
|
|
//---
|
|
//dparam = key
|
|
//soaram = valor
|
|
//lparam = parametro
|
|
if(id == CHARTEVENT_CUSTOM + CHATELGRAM_E_ON_CHANGE_PARAM && fabs(dparam - m_key) < 0.10)
|
|
{
|
|
switch(uint8_t(lparam))
|
|
{
|
|
case TLGM_RECIBER_PARAM_TOKEN:
|
|
{
|
|
if(Token(sparam) != 0)
|
|
{
|
|
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, "No se pudo cambiar el Token del bot");
|
|
}
|
|
break;
|
|
}
|
|
case TLGM_RECIBER_PARAM_CHATID:
|
|
{
|
|
PermitedChats().Clear();
|
|
PermitedChats().Add(long(sparam));
|
|
break;
|
|
}
|
|
case TLGM_RECIBER_PARAM_APIKEY:
|
|
{
|
|
m_agent.ApiKey(sparam);
|
|
break;
|
|
}
|
|
case TLGM_RECIBER_PARAM_MODELNAME:
|
|
{
|
|
m_agent.GetParametersModel().Set("model", sparam, 0);
|
|
|
|
//---
|
|
if(!m_agent.GetInfoModel())
|
|
{
|
|
LogError("Fallo al traer data del modelo modelo", FUNCION_ACTUAL);
|
|
LogWarning("Ingrese su api key y vuelva a modifcar quizas quitar agregar un espacio para que se recuaalr la ventana de contexto",
|
|
FUNCION_ACTUAL);
|
|
}
|
|
|
|
if((m_agent.Flags()&LLMDEF_FLAG_REASONING) != 0)
|
|
{
|
|
// Si tiene lo ocultamos
|
|
m_agent.GetParametersModel().Set("reasoning_format", "hidden", 0);
|
|
}
|
|
else
|
|
{
|
|
// Lo quitamos en caso no lo soporte..
|
|
m_agent.GetParametersModel().Remove("reasoning_format");
|
|
}
|
|
|
|
m_agent.SetCompactMarginExtra(10.0); // 10
|
|
break;
|
|
}
|
|
case TLGM_RECIBER_PARAM_MAXTOKENS:
|
|
{
|
|
m_agent.GetParametersModel().Set("max_completion_tokens", long(sparam));
|
|
break;
|
|
}
|
|
case TLGM_RECIBER_PARAM_CONFIG:
|
|
{
|
|
//---
|
|
string arr[2];
|
|
if(StringSplit(sparam, '|', arr) != 2)
|
|
{
|
|
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, "Fallo al hacer split de config");
|
|
return;
|
|
}
|
|
|
|
//---
|
|
CJsonParser* parser = m_agent.GetJson();
|
|
|
|
//---
|
|
const string fn = arr[TLGM_RECIBIR_PARAM_CONFIG_IDX_FILENAME];
|
|
const int ext = parser.AssingFile(fn,
|
|
(int(arr[TLGM_RECIBIR_PARAM_CONFIG_IDX_FILEFLAGS])&FILE_COMMON)
|
|
!= 0);
|
|
|
|
//---
|
|
if(!parser.AutoParseByFileExt(ext))
|
|
{
|
|
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al parsear json =%s, error=%s", fn,
|
|
::EnumToString(parser.LastErr())));
|
|
return;
|
|
}
|
|
|
|
//---
|
|
CJsonNode root = parser.GetRoot();
|
|
|
|
//--- Acutlizamos la ui
|
|
// Edits bot token
|
|
Token(root["bot_token"].ToString());
|
|
PermitedChats().Clear();
|
|
PermitedChats().Add(root["chat_id"].ToInt(0));
|
|
|
|
//---
|
|
const string apikey = root["api_key"].ToString();
|
|
m_agent.ApiKey(apikey);
|
|
m_agent.GetParametersModel().Set("max_completion_tokens",
|
|
root["max_completion_tokens"].ToInt(0));
|
|
|
|
//---
|
|
m_agent.GetParametersModel().Set("model",
|
|
root["model_name"].ToString(), 0);
|
|
|
|
|
|
//---
|
|
if(!m_agent.GetInfoModel())
|
|
{
|
|
LogError("Fallo al traer info del modelo", FUNCION_ACTUAL);
|
|
}
|
|
|
|
//---
|
|
if((m_agent.Flags()&LLMDEF_FLAG_REASONING) != 0)
|
|
{
|
|
// Si tiene lo ocultamos
|
|
m_agent.GetParametersModel().Set("reasoning_format", "hidden", 0);
|
|
}
|
|
else
|
|
{
|
|
// Lo quitamos en caso no lo soporte..
|
|
m_agent.GetParametersModel().Remove("reasoning_format");
|
|
}
|
|
|
|
//---
|
|
m_agent.SetCompactMarginExtra(10.0); // 10
|
|
break;
|
|
}
|
|
|
|
case TLGM_RECIBER_PARAM_STATE:
|
|
{
|
|
m_in_execution = bool(int(sparam));
|
|
m_first = true;
|
|
FastLog(FUNCION_ACTUAL, INFO_TEXT, StringFormat("Telegram esta: %s", (m_in_execution ? "ejecutandose" : "detenido")));
|
|
break;
|
|
}
|
|
case TLGM_RECIBER_PARAM_SAVE_MEMORY:
|
|
{
|
|
//---
|
|
string arr[2];
|
|
if(StringSplit(sparam, '|', arr) != 2)
|
|
{
|
|
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, "Fallo al hacer split de memory save");
|
|
return;
|
|
}
|
|
|
|
//---
|
|
const string fn = arr[TLGM_RECIBIR_PARAM_CONFIG_IDX_FILENAME];
|
|
|
|
//---
|
|
m_agent.SaveChatHistory(fn, (int(arr[TLGM_RECIBIR_PARAM_CONFIG_IDX_FILEFLAGS])));
|
|
break;
|
|
}
|
|
case TLGM_RECIBER_PARAM_LOAD_MEMORY:
|
|
{
|
|
//---
|
|
string arr[2];
|
|
if(StringSplit(sparam, '|', arr) != 2)
|
|
{
|
|
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, "Fallo al hacer split de memory load");
|
|
return;
|
|
}
|
|
|
|
//---
|
|
const string fn = arr[TLGM_RECIBIR_PARAM_CONFIG_IDX_FILENAME];
|
|
|
|
//---
|
|
m_agent.LoadChatHistory(fn, (int(arr[TLGM_RECIBIR_PARAM_CONFIG_IDX_FILEFLAGS])));
|
|
break;
|
|
}
|
|
default:
|
|
FastLog(FUNCION_ACTUAL, WARNING_TEXT, StringFormat("Tipo de evento desconocido = %I64d", lparam));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CChatTelegramBase::ProcessMessages(void)
|
|
{
|
|
//Print("first");
|
|
for(int i = 0; i < m_chats.Total(); i++)
|
|
{
|
|
//---
|
|
CCustomChat *chat = m_chats.GetNodeAtIndex(i);
|
|
m_chat_id = chat.m_id;
|
|
|
|
//---
|
|
//Print("si");
|
|
if(!chat.m_new_one.done)
|
|
{
|
|
chat.m_new_one.done = true;
|
|
|
|
//---
|
|
// Print("con");
|
|
static string out;
|
|
if(m_agent.Consultar(chat.m_new_one.message_text, out))
|
|
{
|
|
// Print("wsi");
|
|
SendMessage(out, NULL, TELEGRAM_PARSE_MODE_HTML);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CChatTelegramBase::OnTimerEvent(void)
|
|
{
|
|
//---
|
|
if(!m_first)
|
|
return; // Solo si ya alemons se dio por primera vez
|
|
|
|
//--- reading messages
|
|
GetUpdates();
|
|
|
|
//---
|
|
if(m_in_execution)
|
|
{
|
|
ProcessMessages();
|
|
}
|
|
else
|
|
{
|
|
for(int i = 0; i < m_chats.Total(); i++)
|
|
{
|
|
//---
|
|
CCustomChat *chat = m_chats.GetNodeAtIndex(i);
|
|
chat.m_new_one.done = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // AIFULLTAB_SRC_TLG_TLGRECIBER_MQH
|
|
//+------------------------------------------------------------------+
|