Fix: RAg version
This commit is contained in:
parent
f6952e980c
commit
ed3708f42a
|
|
@ -0,0 +1,310 @@
|
||||||
|
VAR Internal
|
||||||
|
Idecon FB_IDECON_Client False False
|
||||||
|
Enable BOOL True False False
|
||||||
|
MsgFilter UINT 17 False False
|
||||||
|
fbTcpConnect SktTCPConnect False False
|
||||||
|
fbSocketSend SktTCPSend False False
|
||||||
|
fbSocketRcv SktTCPRcv False False
|
||||||
|
fbClose SktClose False False
|
||||||
|
Config _sSOCKET_ADDRESS (PortNo := 50000, IpAdr := '172.16.224.200') False False
|
||||||
|
SocketID_Int _sSOCKET False False
|
||||||
|
tmpIpAddress STRING[256] False False
|
||||||
|
tmpPort UINT False False
|
||||||
|
Connected BOOL False False
|
||||||
|
bConnectDone BOOL False False
|
||||||
|
bConnectBusy BOOL False False
|
||||||
|
bConnectError BOOL False False
|
||||||
|
wConnectErrorID WORD False False
|
||||||
|
bSendDone BOOL False False
|
||||||
|
bSendBusy BOOL False False
|
||||||
|
bSendError BOOL False False
|
||||||
|
wSendErrorID WORD False False
|
||||||
|
bRcvDone BOOL False False
|
||||||
|
bRcvBusy BOOL False False
|
||||||
|
bRcvError BOOL False False
|
||||||
|
wRcvErrorID WORD False False
|
||||||
|
RxChunk ARRAY[0..511] OF BYTE False False
|
||||||
|
RxChunkLen UINT False False
|
||||||
|
RxChunkValid BOOL False False
|
||||||
|
RcvTimeout UINT 50 False False
|
||||||
|
TxConsumed BOOL False False
|
||||||
|
prevTxOutValid BOOL False False
|
||||||
|
sendTrigger BOOL False False
|
||||||
|
Command STRING[255] False False
|
||||||
|
CommandTrigger BOOL False False
|
||||||
|
prevCommandTrigger BOOL False False
|
||||||
|
tonPollingSTATSV TON False False
|
||||||
|
tonPollingSTATP TON False False
|
||||||
|
prevPollSVQ BOOL False False
|
||||||
|
prevPollPQ BOOL False False
|
||||||
|
pollResetSV BOOL False False
|
||||||
|
pollResetP BOOL False False
|
||||||
|
prevLastMessage STRING[512] False False
|
||||||
|
newMsg BOOL False False
|
||||||
|
newWeightMsg BOOL False False
|
||||||
|
prevWeightMsg BOOL False False
|
||||||
|
totalRejected DINT False False
|
||||||
|
TxChunk ARRAY[0..511] OF BYTE False False
|
||||||
|
TxChunkLen UINT False False
|
||||||
|
iTx UINT False False
|
||||||
|
TxBuffer ARRAY[0..511] OF BYTE False False
|
||||||
|
tmpWeightData Idecon_WeightData False False
|
||||||
|
tmpStatPData Idecon_StatPData False False
|
||||||
|
rTrigRcv R_TRIG False False
|
||||||
|
bExecuteRcv BOOL False False
|
||||||
|
iRcvState INT False False
|
||||||
|
|
||||||
|
END VAR
|
||||||
|
|
||||||
|
VAR External
|
||||||
|
G_Idecon_Config False
|
||||||
|
G_System_Error False
|
||||||
|
G_ProgressiveID False
|
||||||
|
G_OPCUA_Idecon False
|
||||||
|
G_Idecon_StatP False
|
||||||
|
G_Idecon_LastWeight False
|
||||||
|
G_Idecon_LastSTATSV False
|
||||||
|
G_Idecon_WorkMode False
|
||||||
|
G_Idecon_BatchCode False
|
||||||
|
G_Idecon_ProductionOrder False
|
||||||
|
END VAR
|
||||||
|
|
||||||
|
// ---------- Program ProcessIdecon---------------//
|
||||||
|
|
||||||
|
|
||||||
|
IF NOT Enable THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
RxChunkLen := 0;
|
||||||
|
RxChunkValid := FALSE;
|
||||||
|
TxConsumed := FALSE;
|
||||||
|
Command := '';
|
||||||
|
CommandTrigger := FALSE;
|
||||||
|
prevCommandTrigger := FALSE;
|
||||||
|
prevTxOutValid := FALSE;
|
||||||
|
pollResetSV := FALSE;
|
||||||
|
pollResetP := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
tmpIpAddress := Config.IpAdr;
|
||||||
|
tmpPort := Config.PortNo;
|
||||||
|
|
||||||
|
fbTcpConnect(
|
||||||
|
Execute := (Enable AND NOT Connected),
|
||||||
|
DstAdr := tmpIpAddress, // Passiamo la variabile semplice (FIX per "Member of structure")
|
||||||
|
DstTcpPort := tmpPort, // Passiamo la variabile semplice
|
||||||
|
SrcTcpPort := 0, // (Opzionale) 0 = Assegnazione automatica porta locale
|
||||||
|
Socket => SocketID_Int,
|
||||||
|
Done => bConnectDone,
|
||||||
|
Busy => bConnectBusy,
|
||||||
|
Error => bConnectError,
|
||||||
|
ErrorID => wConnectErrorID
|
||||||
|
);
|
||||||
|
IF bConnectDone THEN
|
||||||
|
Connected := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF bConnectError THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// MACCHINA A STATI "INFINITY LOOP" (Per lettura continua)
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
CASE iRcvState OF
|
||||||
|
0: // STATO IDLE: Pronti a ricevere?
|
||||||
|
// Se siamo connessi e il blocco non è occupato o in errore...
|
||||||
|
IF Connected AND NOT bRcvBusy AND NOT bRcvError THEN
|
||||||
|
bExecuteRcv := TRUE; // ALZA IL FRONTE DI SALITA
|
||||||
|
iRcvState := 10; // Passa in attesa
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
10: // STATO WAIT: Aspetta i dati
|
||||||
|
IF bRcvDone THEN
|
||||||
|
// Dati ricevuti! Andiamo a resettare
|
||||||
|
iRcvState := 20;
|
||||||
|
ELSIF bRcvError OR NOT Connected THEN
|
||||||
|
// Se cade la connessione o c'è errore socket
|
||||||
|
iRcvState := 99;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
20: // STATO RESET (FONDAMENTALE PER LEGGERE IL SUCCESSIVO)
|
||||||
|
bExecuteRcv := FALSE; // Abbassa Execute
|
||||||
|
|
||||||
|
// Aspettiamo che il blocco confermi di essersi spento (Done deve tornare False)
|
||||||
|
// Senza questo check, il riarmo è troppo veloce e fallisce!
|
||||||
|
IF NOT bRcvDone AND NOT bRcvBusy THEN
|
||||||
|
iRcvState := 0; // Torna all'inizio per leggere il prossimo
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
99: // STATO ERRORE
|
||||||
|
bExecuteRcv := FALSE;
|
||||||
|
// Se l'errore sparisce o la connessione cade, resetta la macchina
|
||||||
|
IF NOT bRcvError THEN
|
||||||
|
iRcvState := 0;
|
||||||
|
END_IF;
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
// --- Chiamata al Blocco (Fuori dal CASE) ---
|
||||||
|
fbSocketRcv(
|
||||||
|
Execute := bExecuteRcv,
|
||||||
|
Socket := SocketID_Int,
|
||||||
|
TimeOut := 1, //RcvTimeout, // Assicurati sia basso (es. 10 o 50 ms)
|
||||||
|
Size := UINT#512,
|
||||||
|
RcvDat := RxChunk[0],
|
||||||
|
Done => bRcvDone,
|
||||||
|
Busy => bRcvBusy,
|
||||||
|
Error => bRcvError,
|
||||||
|
ErrorID => wRcvErrorID,
|
||||||
|
RcvSize => RxChunkLen
|
||||||
|
);
|
||||||
|
|
||||||
|
rTrigRcv(CLK := bRcvDone);
|
||||||
|
RxChunkValid := rTrigRcv.Q AND (RxChunkLen > 0);
|
||||||
|
|
||||||
|
// Gestione disconnessione su errore grave
|
||||||
|
IF bRcvError THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
iRcvState := 99;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
tonPollingSTATSV(IN := (Enable AND Connected AND NOT pollResetSV), PT := T#2S);
|
||||||
|
tonPollingSTATP(IN := (Enable AND Connected AND NOT pollResetP), PT := T#5S);
|
||||||
|
|
||||||
|
pollResetSV := FALSE;
|
||||||
|
pollResetP := FALSE;
|
||||||
|
|
||||||
|
CommandTrigger := FALSE;
|
||||||
|
IF tonPollingSTATSV.Q AND NOT prevPollSVQ THEN
|
||||||
|
Command := 'STATSV';
|
||||||
|
CommandTrigger := TRUE;
|
||||||
|
pollResetSV := TRUE;
|
||||||
|
ELSIF tonPollingSTATP.Q AND NOT prevPollPQ THEN
|
||||||
|
Command := 'STATREQ';
|
||||||
|
CommandTrigger := TRUE;
|
||||||
|
pollResetP := TRUE;
|
||||||
|
END_IF;
|
||||||
|
prevPollSVQ := tonPollingSTATSV.Q;
|
||||||
|
prevPollPQ := tonPollingSTATP.Q;
|
||||||
|
|
||||||
|
Idecon(
|
||||||
|
Enable := Enable,
|
||||||
|
MsgFilter := MsgFilter,
|
||||||
|
RxIn := RxChunk,
|
||||||
|
RxInLen := RxChunkLen,
|
||||||
|
RxInValid := RxChunkValid,
|
||||||
|
TxConsumed := TxConsumed,
|
||||||
|
Command := Command,
|
||||||
|
CommandTrigger := CommandTrigger
|
||||||
|
);
|
||||||
|
tmpWeightData := Idecon.Weight;
|
||||||
|
tmpStatPData := Idecon.StatP;
|
||||||
|
// Gestione Messaggi
|
||||||
|
newMsg := (Idecon.LastMessage <> prevLastMessage);
|
||||||
|
prevLastMessage := Idecon.LastMessage;
|
||||||
|
|
||||||
|
newWeightMsg := newMsg AND IDECON_StartsWith(Idecon.LastMessage, 'WEIGHT=');
|
||||||
|
|
||||||
|
IF newWeightMsg AND NOT prevWeightMsg THEN
|
||||||
|
G_ProgressiveID := G_ProgressiveID + 1;
|
||||||
|
END_IF;
|
||||||
|
prevWeightMsg := newWeightMsg;
|
||||||
|
G_Idecon_LastSTATSV := Idecon.LastSTATSV;
|
||||||
|
|
||||||
|
|
||||||
|
IF tmpWeightData.Valid THEN
|
||||||
|
G_Idecon_LastWeight.DateTimeText := tmpWeightData.DateTimeText;
|
||||||
|
G_Idecon_LastWeight.ProductionOrder := tmpWeightData.ProductionOrder;
|
||||||
|
G_Idecon_LastWeight.BatchCode := tmpWeightData.BatchCode;
|
||||||
|
G_Idecon_LastWeight.RecipeName := tmpWeightData.RecipeName;
|
||||||
|
G_Idecon_LastWeight.LineCode := tmpWeightData.LineCode;
|
||||||
|
G_Idecon_LastWeight.SerialNumber := tmpWeightData.SerialNumber;
|
||||||
|
G_Idecon_LastWeight.WeightMg := tmpWeightData.WeightMg;
|
||||||
|
G_Idecon_LastWeight.DeltaToNominalMg:= tmpWeightData.DeltaToNominalMg;
|
||||||
|
G_Idecon_LastWeight.Classification := tmpWeightData.Classification;
|
||||||
|
G_Idecon_LastWeight.Valid := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// --- E anche qui usiamo tmpStatPData ---
|
||||||
|
IF tmpStatPData.Valid THEN
|
||||||
|
G_Idecon_StatP.TotalProducts := tmpStatPData.TotalProducts;
|
||||||
|
G_Idecon_StatP.TotalAccepted := tmpStatPData.TotalAccepted;
|
||||||
|
G_Idecon_StatP.RejectedMinus := tmpStatPData.RejectedMinus;
|
||||||
|
G_Idecon_StatP.RejectedMinusMinus := tmpStatPData.RejectedMinusMinus;
|
||||||
|
G_Idecon_StatP.RejectedPlus := tmpStatPData.RejectedPlus;
|
||||||
|
G_Idecon_StatP.RejectedPlusPlus := tmpStatPData.RejectedPlusPlus;
|
||||||
|
G_Idecon_StatP.CannotBeWeighed := tmpStatPData.CannotBeWeighed;
|
||||||
|
G_Idecon_StatP.MetalCategory := tmpStatPData.MetalCategory;
|
||||||
|
G_Idecon_StatP.Valid := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
|
||||||
|
G_System_Error := bConnectError OR bSendError OR bRcvError OR Idecon.Error;
|
||||||
|
|
||||||
|
IF G_Idecon_StatP.Valid AND (G_Idecon_StatP.TotalProducts >= G_Idecon_StatP.TotalAccepted) THEN
|
||||||
|
totalRejected := G_Idecon_StatP.TotalProducts - G_Idecon_StatP.TotalAccepted;
|
||||||
|
ELSE
|
||||||
|
totalRejected := 0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// OPC UA Mapping
|
||||||
|
G_OPCUA_Idecon.Connected := Connected;
|
||||||
|
G_OPCUA_Idecon.WorkMode := G_Idecon_WorkMode;
|
||||||
|
G_OPCUA_Idecon.LastSTATSV := G_Idecon_LastSTATSV;
|
||||||
|
G_OPCUA_Idecon.BatchCode := G_Idecon_BatchCode;
|
||||||
|
G_OPCUA_Idecon.ProductionOrder := G_Idecon_ProductionOrder;
|
||||||
|
G_OPCUA_Idecon.Error := G_System_Error;
|
||||||
|
G_OPCUA_Idecon.ErrorId := UINT_TO_UDINT(WORD_TO_UINT(wConnectErrorID));
|
||||||
|
|
||||||
|
G_OPCUA_Idecon.LastWeight.ProgressiveId := G_ProgressiveID;
|
||||||
|
G_OPCUA_Idecon.LastWeight.TimestampText := G_Idecon_LastWeight.DateTimeText;
|
||||||
|
G_OPCUA_Idecon.LastWeight.ProductionOrder := G_Idecon_LastWeight.ProductionOrder;
|
||||||
|
G_OPCUA_Idecon.LastWeight.BatchCode := G_Idecon_LastWeight.BatchCode;
|
||||||
|
G_OPCUA_Idecon.LastWeight.RecipeName := G_Idecon_LastWeight.RecipeName;
|
||||||
|
G_OPCUA_Idecon.LastWeight.LineCode := G_Idecon_LastWeight.LineCode;
|
||||||
|
G_OPCUA_Idecon.LastWeight.SerialNumber := G_Idecon_LastWeight.SerialNumber;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Weight_g := DINT_TO_LREAL(G_Idecon_LastWeight.WeightMg) / LREAL#1000.0;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Delta_g := DINT_TO_LREAL(G_Idecon_LastWeight.DeltaToNominalMg) / LREAL#1000.0;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Classification := G_Idecon_LastWeight.Classification;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Expelled := FALSE;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Valid := G_Idecon_LastWeight.Valid;
|
||||||
|
|
||||||
|
G_OPCUA_Idecon.Stats.TotalProducts := G_Idecon_StatP.TotalProducts;
|
||||||
|
G_OPCUA_Idecon.Stats.TotalAccepted := G_Idecon_StatP.TotalAccepted;
|
||||||
|
G_OPCUA_Idecon.Stats.TotalRejected := totalRejected;
|
||||||
|
G_OPCUA_Idecon.Stats.RejectedPlusPlus := G_Idecon_StatP.RejectedPlusPlus;
|
||||||
|
G_OPCUA_Idecon.Stats.CannotBeWeighed := G_Idecon_StatP.CannotBeWeighed;
|
||||||
|
G_OPCUA_Idecon.Stats.MetalCategory := G_Idecon_StatP.MetalCategory;
|
||||||
|
G_OPCUA_Idecon.Stats.Valid := G_Idecon_StatP.Valid;
|
||||||
|
|
||||||
|
// Invio Socket
|
||||||
|
sendTrigger := (Idecon.TxOutValid AND NOT prevTxOutValid);
|
||||||
|
prevTxOutValid := Idecon.TxOutValid;
|
||||||
|
|
||||||
|
IF sendTrigger THEN
|
||||||
|
// Copiamo i dati dall'output dell'FB al buffer LOCALE
|
||||||
|
// Questo evita l'errore "Member of function block instance variable"
|
||||||
|
TxBuffer := Idecon.TxOut;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
fbSocketSend(
|
||||||
|
Execute := (Enable AND Connected AND sendTrigger),
|
||||||
|
Socket := SocketID_Int,
|
||||||
|
SendDat := TxBuffer[0], // --- CORREZIONE 2: Usa buffer locale ---
|
||||||
|
Size := Idecon.TxOutLen,
|
||||||
|
Done => bSendDone,
|
||||||
|
Busy => bSendBusy,
|
||||||
|
Error => bSendError,
|
||||||
|
ErrorID => wSendErrorID
|
||||||
|
);
|
||||||
|
|
||||||
|
TxConsumed := bSendDone;
|
||||||
|
|
||||||
|
IF bSendError THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
fbClose(
|
||||||
|
Execute := (Enable AND NOT Connected),
|
||||||
|
Socket := SocketID_Int
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,310 @@
|
||||||
|
VAR Internal
|
||||||
|
Idecon FB_IDECON_Client False False
|
||||||
|
Enable BOOL True False False
|
||||||
|
MsgFilter UINT 17 False False
|
||||||
|
fbTcpConnect SktTCPConnect False False
|
||||||
|
fbSocketSend SktTCPSend False False
|
||||||
|
fbSocketRcv SktTCPRcv False False
|
||||||
|
fbClose SktClose False False
|
||||||
|
Config _sSOCKET_ADDRESS (PortNo := 50000, IpAdr := '172.16.224.200') False False
|
||||||
|
SocketID_Int _sSOCKET False False
|
||||||
|
tmpIpAddress STRING[256] False False
|
||||||
|
tmpPort UINT False False
|
||||||
|
Connected BOOL False False
|
||||||
|
bConnectDone BOOL False False
|
||||||
|
bConnectBusy BOOL False False
|
||||||
|
bConnectError BOOL False False
|
||||||
|
wConnectErrorID WORD False False
|
||||||
|
bSendDone BOOL False False
|
||||||
|
bSendBusy BOOL False False
|
||||||
|
bSendError BOOL False False
|
||||||
|
wSendErrorID WORD False False
|
||||||
|
bRcvDone BOOL False False
|
||||||
|
bRcvBusy BOOL False False
|
||||||
|
bRcvError BOOL False False
|
||||||
|
wRcvErrorID WORD False False
|
||||||
|
RxChunk ARRAY[0..511] OF BYTE False False
|
||||||
|
RxChunkLen UINT False False
|
||||||
|
RxChunkValid BOOL False False
|
||||||
|
RcvTimeout UINT 50 False False
|
||||||
|
TxConsumed BOOL False False
|
||||||
|
prevTxOutValid BOOL False False
|
||||||
|
sendTrigger BOOL False False
|
||||||
|
Command STRING[255] False False
|
||||||
|
CommandTrigger BOOL False False
|
||||||
|
prevCommandTrigger BOOL False False
|
||||||
|
tonPollingSTATSV TON False False
|
||||||
|
tonPollingSTATP TON False False
|
||||||
|
prevPollSVQ BOOL False False
|
||||||
|
prevPollPQ BOOL False False
|
||||||
|
pollResetSV BOOL False False
|
||||||
|
pollResetP BOOL False False
|
||||||
|
prevLastMessage STRING[512] False False
|
||||||
|
newMsg BOOL False False
|
||||||
|
newWeightMsg BOOL False False
|
||||||
|
prevWeightMsg BOOL False False
|
||||||
|
totalRejected DINT False False
|
||||||
|
TxChunk ARRAY[0..511] OF BYTE False False
|
||||||
|
TxChunkLen UINT False False
|
||||||
|
iTx UINT False False
|
||||||
|
TxBuffer ARRAY[0..511] OF BYTE False False
|
||||||
|
tmpWeightData Idecon_WeightData False False
|
||||||
|
tmpStatPData Idecon_StatPData False False
|
||||||
|
rTrigRcv R_TRIG False False
|
||||||
|
bExecuteRcv BOOL False False
|
||||||
|
iRcvState INT False False
|
||||||
|
|
||||||
|
END VAR
|
||||||
|
|
||||||
|
VAR External
|
||||||
|
G_Idecon_Config False
|
||||||
|
G_System_Error False
|
||||||
|
G_ProgressiveID False
|
||||||
|
G_OPCUA_Idecon False
|
||||||
|
G_Idecon_StatP False
|
||||||
|
G_Idecon_LastWeight False
|
||||||
|
G_Idecon_LastSTATSV False
|
||||||
|
G_Idecon_WorkMode False
|
||||||
|
G_Idecon_BatchCode False
|
||||||
|
G_Idecon_ProductionOrder False
|
||||||
|
END VAR
|
||||||
|
|
||||||
|
// ---------- Program ProcessIdecon---------------//
|
||||||
|
|
||||||
|
|
||||||
|
IF NOT Enable THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
RxChunkLen := 0;
|
||||||
|
RxChunkValid := FALSE;
|
||||||
|
TxConsumed := FALSE;
|
||||||
|
Command := '';
|
||||||
|
CommandTrigger := FALSE;
|
||||||
|
prevCommandTrigger := FALSE;
|
||||||
|
prevTxOutValid := FALSE;
|
||||||
|
pollResetSV := FALSE;
|
||||||
|
pollResetP := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
tmpIpAddress := Config.IpAdr;
|
||||||
|
tmpPort := Config.PortNo;
|
||||||
|
|
||||||
|
fbTcpConnect(
|
||||||
|
Execute := (Enable AND NOT Connected),
|
||||||
|
DstAdr := tmpIpAddress, // Passiamo la variabile semplice (FIX per "Member of structure")
|
||||||
|
DstTcpPort := tmpPort, // Passiamo la variabile semplice
|
||||||
|
SrcTcpPort := 0, // (Opzionale) 0 = Assegnazione automatica porta locale
|
||||||
|
Socket => SocketID_Int,
|
||||||
|
Done => bConnectDone,
|
||||||
|
Busy => bConnectBusy,
|
||||||
|
Error => bConnectError,
|
||||||
|
ErrorID => wConnectErrorID
|
||||||
|
);
|
||||||
|
IF bConnectDone THEN
|
||||||
|
Connected := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF bConnectError THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// MACCHINA A STATI "INFINITY LOOP" (Per lettura continua)
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
CASE iRcvState OF
|
||||||
|
0: // STATO IDLE: Pronti a ricevere?
|
||||||
|
// Se siamo connessi e il blocco non è occupato o in errore...
|
||||||
|
IF Connected AND NOT bRcvBusy AND NOT bRcvError THEN
|
||||||
|
bExecuteRcv := TRUE; // ALZA IL FRONTE DI SALITA
|
||||||
|
iRcvState := 10; // Passa in attesa
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
10: // STATO WAIT: Aspetta i dati
|
||||||
|
IF bRcvDone THEN
|
||||||
|
// Dati ricevuti! Andiamo a resettare
|
||||||
|
iRcvState := 20;
|
||||||
|
ELSIF bRcvError OR NOT Connected THEN
|
||||||
|
// Se cade la connessione o c'è errore socket
|
||||||
|
iRcvState := 99;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
20: // STATO RESET (FONDAMENTALE PER LEGGERE IL SUCCESSIVO)
|
||||||
|
bExecuteRcv := FALSE; // Abbassa Execute
|
||||||
|
|
||||||
|
// Aspettiamo che il blocco confermi di essersi spento (Done deve tornare False)
|
||||||
|
// Senza questo check, il riarmo è troppo veloce e fallisce!
|
||||||
|
IF NOT bRcvDone AND NOT bRcvBusy THEN
|
||||||
|
iRcvState := 0; // Torna all'inizio per leggere il prossimo
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
99: // STATO ERRORE
|
||||||
|
bExecuteRcv := FALSE;
|
||||||
|
// Se l'errore sparisce o la connessione cade, resetta la macchina
|
||||||
|
IF NOT bRcvError THEN
|
||||||
|
iRcvState := 0;
|
||||||
|
END_IF;
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
// --- Chiamata al Blocco (Fuori dal CASE) ---
|
||||||
|
fbSocketRcv(
|
||||||
|
Execute := bExecuteRcv,
|
||||||
|
Socket := SocketID_Int,
|
||||||
|
TimeOut := 1, //RcvTimeout, // Assicurati sia basso (es. 10 o 50 ms)
|
||||||
|
Size := UINT#512,
|
||||||
|
RcvDat := RxChunk[0],
|
||||||
|
Done => bRcvDone,
|
||||||
|
Busy => bRcvBusy,
|
||||||
|
Error => bRcvError,
|
||||||
|
ErrorID => wRcvErrorID,
|
||||||
|
RcvSize => RxChunkLen
|
||||||
|
);
|
||||||
|
|
||||||
|
rTrigRcv(CLK := bRcvDone);
|
||||||
|
RxChunkValid := rTrigRcv.Q AND (RxChunkLen > 0);
|
||||||
|
|
||||||
|
// Gestione disconnessione su errore grave
|
||||||
|
IF bRcvError THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
iRcvState := 99;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
tonPollingSTATSV(IN := (Enable AND Connected AND NOT pollResetSV), PT := T#2S);
|
||||||
|
tonPollingSTATP(IN := (Enable AND Connected AND NOT pollResetP), PT := T#5S);
|
||||||
|
|
||||||
|
pollResetSV := FALSE;
|
||||||
|
pollResetP := FALSE;
|
||||||
|
|
||||||
|
CommandTrigger := FALSE;
|
||||||
|
IF tonPollingSTATSV.Q AND NOT prevPollSVQ THEN
|
||||||
|
Command := 'STATSV';
|
||||||
|
CommandTrigger := TRUE;
|
||||||
|
pollResetSV := TRUE;
|
||||||
|
ELSIF tonPollingSTATP.Q AND NOT prevPollPQ THEN
|
||||||
|
Command := 'STATREQ';
|
||||||
|
CommandTrigger := TRUE;
|
||||||
|
pollResetP := TRUE;
|
||||||
|
END_IF;
|
||||||
|
prevPollSVQ := tonPollingSTATSV.Q;
|
||||||
|
prevPollPQ := tonPollingSTATP.Q;
|
||||||
|
|
||||||
|
Idecon(
|
||||||
|
Enable := Enable,
|
||||||
|
MsgFilter := MsgFilter,
|
||||||
|
RxIn := RxChunk,
|
||||||
|
RxInLen := RxChunkLen,
|
||||||
|
RxInValid := RxChunkValid,
|
||||||
|
TxConsumed := TxConsumed,
|
||||||
|
Command := Command,
|
||||||
|
CommandTrigger := CommandTrigger
|
||||||
|
);
|
||||||
|
tmpWeightData := Idecon.Weight;
|
||||||
|
tmpStatPData := Idecon.StatP;
|
||||||
|
// Gestione Messaggi
|
||||||
|
newMsg := (Idecon.LastMessage <> prevLastMessage);
|
||||||
|
prevLastMessage := Idecon.LastMessage;
|
||||||
|
|
||||||
|
newWeightMsg := newMsg AND IDECON_StartsWith(Idecon.LastMessage, 'WEIGHT=');
|
||||||
|
|
||||||
|
IF newWeightMsg AND NOT prevWeightMsg THEN
|
||||||
|
G_ProgressiveID := G_ProgressiveID + 1;
|
||||||
|
END_IF;
|
||||||
|
prevWeightMsg := newWeightMsg;
|
||||||
|
G_Idecon_LastSTATSV := Idecon.LastSTATSV;
|
||||||
|
|
||||||
|
|
||||||
|
IF tmpWeightData.Valid THEN
|
||||||
|
G_Idecon_LastWeight.DateTimeText := tmpWeightData.DateTimeText;
|
||||||
|
G_Idecon_LastWeight.ProductionOrder := tmpWeightData.ProductionOrder;
|
||||||
|
G_Idecon_LastWeight.BatchCode := tmpWeightData.BatchCode;
|
||||||
|
G_Idecon_LastWeight.RecipeName := tmpWeightData.RecipeName;
|
||||||
|
G_Idecon_LastWeight.LineCode := tmpWeightData.LineCode;
|
||||||
|
G_Idecon_LastWeight.SerialNumber := tmpWeightData.SerialNumber;
|
||||||
|
G_Idecon_LastWeight.WeightMg := tmpWeightData.WeightMg;
|
||||||
|
G_Idecon_LastWeight.DeltaToNominalMg:= tmpWeightData.DeltaToNominalMg;
|
||||||
|
G_Idecon_LastWeight.Classification := tmpWeightData.Classification;
|
||||||
|
G_Idecon_LastWeight.Valid := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// --- E anche qui usiamo tmpStatPData ---
|
||||||
|
IF tmpStatPData.Valid THEN
|
||||||
|
G_Idecon_StatP.TotalProducts := tmpStatPData.TotalProducts;
|
||||||
|
G_Idecon_StatP.TotalAccepted := tmpStatPData.TotalAccepted;
|
||||||
|
G_Idecon_StatP.RejectedMinus := tmpStatPData.RejectedMinus;
|
||||||
|
G_Idecon_StatP.RejectedMinusMinus := tmpStatPData.RejectedMinusMinus;
|
||||||
|
G_Idecon_StatP.RejectedPlus := tmpStatPData.RejectedPlus;
|
||||||
|
G_Idecon_StatP.RejectedPlusPlus := tmpStatPData.RejectedPlusPlus;
|
||||||
|
G_Idecon_StatP.CannotBeWeighed := tmpStatPData.CannotBeWeighed;
|
||||||
|
G_Idecon_StatP.MetalCategory := tmpStatPData.MetalCategory;
|
||||||
|
G_Idecon_StatP.Valid := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
|
||||||
|
G_System_Error := bConnectError OR bSendError OR bRcvError OR Idecon.Error;
|
||||||
|
|
||||||
|
IF G_Idecon_StatP.Valid AND (G_Idecon_StatP.TotalProducts >= G_Idecon_StatP.TotalAccepted) THEN
|
||||||
|
totalRejected := G_Idecon_StatP.TotalProducts - G_Idecon_StatP.TotalAccepted;
|
||||||
|
ELSE
|
||||||
|
totalRejected := 0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// OPC UA Mapping
|
||||||
|
G_OPCUA_Idecon.Connected := Connected;
|
||||||
|
G_OPCUA_Idecon.WorkMode := G_Idecon_WorkMode;
|
||||||
|
G_OPCUA_Idecon.LastSTATSV := G_Idecon_LastSTATSV;
|
||||||
|
G_OPCUA_Idecon.BatchCode := G_Idecon_BatchCode;
|
||||||
|
G_OPCUA_Idecon.ProductionOrder := G_Idecon_ProductionOrder;
|
||||||
|
G_OPCUA_Idecon.Error := G_System_Error;
|
||||||
|
G_OPCUA_Idecon.ErrorId := UINT_TO_UDINT(WORD_TO_UINT(wConnectErrorID));
|
||||||
|
|
||||||
|
G_OPCUA_Idecon.LastWeight.ProgressiveId := G_ProgressiveID;
|
||||||
|
G_OPCUA_Idecon.LastWeight.TimestampText := G_Idecon_LastWeight.DateTimeText;
|
||||||
|
G_OPCUA_Idecon.LastWeight.ProductionOrder := G_Idecon_LastWeight.ProductionOrder;
|
||||||
|
G_OPCUA_Idecon.LastWeight.BatchCode := G_Idecon_LastWeight.BatchCode;
|
||||||
|
G_OPCUA_Idecon.LastWeight.RecipeName := G_Idecon_LastWeight.RecipeName;
|
||||||
|
G_OPCUA_Idecon.LastWeight.LineCode := G_Idecon_LastWeight.LineCode;
|
||||||
|
G_OPCUA_Idecon.LastWeight.SerialNumber := G_Idecon_LastWeight.SerialNumber;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Weight_g := DINT_TO_LREAL(G_Idecon_LastWeight.WeightMg) / LREAL#1000.0;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Delta_g := DINT_TO_LREAL(G_Idecon_LastWeight.DeltaToNominalMg) / LREAL#1000.0;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Classification := G_Idecon_LastWeight.Classification;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Expelled := FALSE;
|
||||||
|
G_OPCUA_Idecon.LastWeight.Valid := G_Idecon_LastWeight.Valid;
|
||||||
|
|
||||||
|
G_OPCUA_Idecon.Stats.TotalProducts := G_Idecon_StatP.TotalProducts;
|
||||||
|
G_OPCUA_Idecon.Stats.TotalAccepted := G_Idecon_StatP.TotalAccepted;
|
||||||
|
G_OPCUA_Idecon.Stats.TotalRejected := totalRejected;
|
||||||
|
G_OPCUA_Idecon.Stats.RejectedPlusPlus := G_Idecon_StatP.RejectedPlusPlus;
|
||||||
|
G_OPCUA_Idecon.Stats.CannotBeWeighed := G_Idecon_StatP.CannotBeWeighed;
|
||||||
|
G_OPCUA_Idecon.Stats.MetalCategory := G_Idecon_StatP.MetalCategory;
|
||||||
|
G_OPCUA_Idecon.Stats.Valid := G_Idecon_StatP.Valid;
|
||||||
|
|
||||||
|
// Invio Socket
|
||||||
|
sendTrigger := (Idecon.TxOutValid AND NOT prevTxOutValid);
|
||||||
|
prevTxOutValid := Idecon.TxOutValid;
|
||||||
|
|
||||||
|
IF sendTrigger THEN
|
||||||
|
// Copiamo i dati dall'output dell'FB al buffer LOCALE
|
||||||
|
// Questo evita l'errore "Member of function block instance variable"
|
||||||
|
TxBuffer := Idecon.TxOut;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
fbSocketSend(
|
||||||
|
Execute := (Enable AND Connected AND sendTrigger),
|
||||||
|
Socket := SocketID_Int,
|
||||||
|
SendDat := TxBuffer[0], // --- CORREZIONE 2: Usa buffer locale ---
|
||||||
|
Size := Idecon.TxOutLen,
|
||||||
|
Done => bSendDone,
|
||||||
|
Busy => bSendBusy,
|
||||||
|
Error => bSendError,
|
||||||
|
ErrorID => wSendErrorID
|
||||||
|
);
|
||||||
|
|
||||||
|
TxConsumed := bSendDone;
|
||||||
|
|
||||||
|
IF bSendError THEN
|
||||||
|
Connected := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
fbClose(
|
||||||
|
Execute := (Enable AND NOT Connected),
|
||||||
|
Socket := SocketID_Int
|
||||||
|
);
|
||||||
Binary file not shown.
95
app.py
95
app.py
|
|
@ -4,10 +4,14 @@ import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import shutil
|
import shutil
|
||||||
import uuid
|
import uuid
|
||||||
import ollama # Import spostato all'inizio per efficienza
|
import ollama
|
||||||
from qdrant_client import QdrantClient
|
from qdrant_client import QdrantClient
|
||||||
from qdrant_client.http.models import PointStruct
|
from qdrant_client.http.models import PointStruct
|
||||||
|
|
||||||
|
# --- CONFIGURAZIONE HARD-CODED PER ROMPERE IL BLOCCO 127.0.0.1 ---
|
||||||
|
OLLAMA_URL = "http://192.168.1.243:11434"
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
# Define user roles mapping
|
# Define user roles mapping
|
||||||
USER_ROLES = {
|
USER_ROLES = {
|
||||||
'moglie@esempio.com': 'business',
|
'moglie@esempio.com': 'business',
|
||||||
|
|
@ -45,7 +49,7 @@ async def connect_to_qdrant():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client.get_collection(collection_name)
|
client.get_collection(collection_name)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
client.create_collection(
|
client.create_collection(
|
||||||
collection_name=collection_name,
|
collection_name=collection_name,
|
||||||
vectors_config={"size": 768, "distance": "Cosine"}
|
vectors_config={"size": 768, "distance": "Cosine"}
|
||||||
|
|
@ -54,31 +58,35 @@ async def connect_to_qdrant():
|
||||||
return client
|
return client
|
||||||
|
|
||||||
async def get_embeddings(text):
|
async def get_embeddings(text):
|
||||||
# --- CORREZIONE CRITICA ---
|
# --- FIX: Splitto Host e Port per evitare confusione ---
|
||||||
# Inizializza il client usando l'URL completo (come in message), NON 'host=...'
|
client = ollama.Client(host=OLLAMA_URL) # Uso l'URL intero
|
||||||
# Questo evita l'errore "127.0.0.1:porta casuale"
|
|
||||||
ollama_api_base = os.getenv('OLLAMA_API_BASE', 'http://192.168.1.243:11434')
|
|
||||||
client = ollama.Client(ollama_api_base)
|
|
||||||
|
|
||||||
# Controllo lunghezza testo
|
# Controllo lunghezza testo
|
||||||
if len(text) > 12000:
|
if len(text) > 12000:
|
||||||
text = text[:12000]
|
text = text[:12000]
|
||||||
|
|
||||||
response = client.embed(model='nomic-embed-text', input=text)
|
try:
|
||||||
|
response = client.embed(model='nomic-embed-text', input=text)
|
||||||
|
|
||||||
# Gestione compatibilità risposta (embedding vs embeddings)
|
# Gestione risposta
|
||||||
if 'embeddings' in response:
|
if 'embeddings' in response:
|
||||||
return response['embeddings'][0]
|
return response['embeddings'][0]
|
||||||
return response['embedding']
|
return response.get('embedding')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Errore Embedding: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
# Nuova funzione per CERCARE nei documenti (RAG)
|
|
||||||
async def search_qdrant(query_text, user_role):
|
async def search_qdrant(query_text, user_role):
|
||||||
"""Cerca documenti pertinenti su Qdrant"""
|
"""Cerca documenti pertinenti su Qdrant"""
|
||||||
try:
|
try:
|
||||||
qdrant_client = await connect_to_qdrant()
|
qdrant_client = await connect_to_qdrant()
|
||||||
query_embedding = await get_embeddings(query_text)
|
query_embedding = await get_embeddings(query_text)
|
||||||
|
|
||||||
# Cerca i 3 documenti più simili alla domanda
|
# Se non trova embedding (errore connessione), non cercare
|
||||||
|
if not query_embedding:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Cerca i 3 documenti più simili
|
||||||
search_result = qdrant_client.search(
|
search_result = qdrant_client.search(
|
||||||
collection_name="documents",
|
collection_name="documents",
|
||||||
query_vector=query_embedding,
|
query_vector=query_embedding,
|
||||||
|
|
@ -86,33 +94,31 @@ async def search_qdrant(query_text, user_role):
|
||||||
)
|
)
|
||||||
|
|
||||||
contexts = []
|
contexts = []
|
||||||
for hit in search_result:
|
# FIX: controllo sicurezza per evitare 'list index out of range'
|
||||||
if 'payload' in hit and 'file_name' in hit['payload']:
|
if search_result:
|
||||||
contexts.append(f"Documento: {hit['payload']['file_name']}")
|
for hit in search_result:
|
||||||
|
try:
|
||||||
|
if 'payload' in hit and 'file_name' in hit['payload']:
|
||||||
|
contexts.append(f"Documento: {hit['payload']['file_name']}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
return "\n".join(contexts)
|
return "\n".join(contexts)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Errore ricerca: {e}")
|
print(f"Errore ricerca Qdrant: {e}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@cl.on_chat_start
|
@cl.on_chat_start
|
||||||
async def chat_start():
|
async def chat_start():
|
||||||
# Set the user's email to a hardcoded value for testing purposes
|
# Hardcode per test
|
||||||
user_email = "admin@esempio.com"
|
user_email = "admin@esempio.com"
|
||||||
|
|
||||||
# Determine the user's role based on the email
|
|
||||||
user_role = USER_ROLES.get(user_email, 'guest')
|
user_role = USER_ROLES.get(user_email, 'guest')
|
||||||
|
|
||||||
# Create workspace directory if it doesn't exist
|
|
||||||
create_workspace(user_role)
|
create_workspace(user_role)
|
||||||
|
|
||||||
# Initialize history in the session
|
|
||||||
cl.user_session.set("history", [])
|
cl.user_session.set("history", [])
|
||||||
|
|
||||||
# Set the user's role in the session
|
|
||||||
cl.user_session.set("role", user_role)
|
cl.user_session.set("role", user_role)
|
||||||
|
|
||||||
# Send a welcome message based on the user's role
|
|
||||||
if user_role == 'admin':
|
if user_role == 'admin':
|
||||||
await cl.Message(content="Welcome, Admin!").send()
|
await cl.Message(content="Welcome, Admin!").send()
|
||||||
elif user_role == 'engineering':
|
elif user_role == 'engineering':
|
||||||
|
|
@ -126,56 +132,51 @@ async def chat_start():
|
||||||
|
|
||||||
@cl.on_message
|
@cl.on_message
|
||||||
async def message(message):
|
async def message(message):
|
||||||
# Retrieve the user's role from the session
|
|
||||||
user_role = cl.user_session.get("role", 'guest')
|
user_role = cl.user_session.get("role", 'guest')
|
||||||
|
|
||||||
if not user_role:
|
if not user_role:
|
||||||
await cl.Message(content="User role not found").send()
|
await cl.Message(content="User role not found").send()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Initialize the Ollama client
|
|
||||||
ollama_api_base = os.getenv('OLLAMA_API_BASE', 'http://192.168.1.243:11434')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client = ollama.Client(ollama_api_base)
|
# Client Ollama URL Hardcoded
|
||||||
|
client = ollama.Client(host=OLLAMA_URL)
|
||||||
|
|
||||||
# Retrieve the history from the session and limit it
|
# History & Sliding Window
|
||||||
history = cl.user_session.get("history", [])
|
history = cl.user_session.get("history", [])
|
||||||
history = limit_history(history)
|
history = limit_history(history)
|
||||||
|
|
||||||
# --- RAG STEP: Cerca nei documenti prima di chattare ---
|
# --- RAG STEP 1: Cerca nei documenti ---
|
||||||
context_text = await search_qdrant(message.content, user_role)
|
context_text = await search_qdrant(message.content, user_role)
|
||||||
|
|
||||||
# Se trova documenti, inietta il contesto come "System Message"
|
# Se trova contesto, iniettalo
|
||||||
if context_text:
|
if context_text:
|
||||||
system_prompt = f"Contexto dai documenti:\n{context_text}\n\nRispondi usando questo contesto."
|
system_prompt = f"Contexto dai documenti:\n{context_text}\n\nRispondi usando questo contesto."
|
||||||
history.insert(0, {"role": "system", "content": system_prompt})
|
history.insert(0, {"role": "system", "content": system_prompt})
|
||||||
|
|
||||||
# Append the new user message to the history
|
|
||||||
history.append({"role": "user", "content": message.content})
|
history.append({"role": "user", "content": message.content})
|
||||||
|
|
||||||
# Check for Uploads
|
# Gestione Upload e Indexing
|
||||||
if message.elements:
|
if message.elements:
|
||||||
uploaded_files = []
|
uploaded_files = []
|
||||||
for element in message.elements:
|
for element in message.elements:
|
||||||
try:
|
try:
|
||||||
# Save file to disk
|
|
||||||
dest_path = os.path.join(WORKSPACES_DIR, user_role, element.name)
|
dest_path = os.path.join(WORKSPACES_DIR, user_role, element.name)
|
||||||
with open(element.path, 'rb') as src, open(dest_path, 'wb') as dst:
|
with open(element.path, 'rb') as src, open(dest_path, 'wb') as dst:
|
||||||
shutil.copyfileobj(src, dst)
|
shutil.copyfileobj(src, dst)
|
||||||
|
|
||||||
# Indexing on Qdrant if .txt
|
|
||||||
if element.name.endswith('.txt'):
|
if element.name.endswith('.txt'):
|
||||||
with open(dest_path, 'r') as f:
|
with open(dest_path, 'r') as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
|
# Indexing
|
||||||
embeddings = await get_embeddings(content)
|
embeddings = await get_embeddings(content)
|
||||||
qdrant_client = await connect_to_qdrant()
|
if embeddings:
|
||||||
point_id = uuid.uuid4()
|
qdrant_client = await connect_to_qdrant()
|
||||||
point = PointStruct(id=point_id, vector=embeddings, payload={"file_name": element.name})
|
point_id = uuid.uuid4()
|
||||||
qdrant_client.upsert(collection_name="documents", points=[point])
|
point = PointStruct(id=point_id, vector=embeddings, payload={"file_name": element.name})
|
||||||
|
qdrant_client.upsert(collection_name="documents", points=[point])
|
||||||
await cl.Message(content=f"Documento '{element.name}' indicizzato.").send()
|
await cl.Message(content=f"Documento '{element.name}' indicizzato.").send()
|
||||||
|
|
||||||
uploaded_files.append(element.name)
|
uploaded_files.append(element.name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -184,10 +185,10 @@ async def message(message):
|
||||||
if uploaded_files:
|
if uploaded_files:
|
||||||
await cl.Message(content=f"Files saved: {', '.join(uploaded_files)}").send()
|
await cl.Message(content=f"Files saved: {', '.join(uploaded_files)}").send()
|
||||||
|
|
||||||
# Call the model
|
# Chat
|
||||||
response = client.chat(model='qwen2.5-coder:7b', messages=history)
|
response = client.chat(model='qwen2.5-coder:7b', messages=history)
|
||||||
|
|
||||||
# Extract code blocks
|
# Code Extracting
|
||||||
code_blocks = re.findall(r"```python(.*?)```", response['message']['content'], re.DOTALL)
|
code_blocks = re.findall(r"```python(.*?)```", response['message']['content'], re.DOTALL)
|
||||||
|
|
||||||
elements = []
|
elements = []
|
||||||
|
|
@ -196,11 +197,9 @@ async def message(message):
|
||||||
file_path = save_code_to_file(code, user_role)
|
file_path = save_code_to_file(code, user_role)
|
||||||
elements.append(cl.File(name=os.path.basename(file_path), path=file_path))
|
elements.append(cl.File(name=os.path.basename(file_path), path=file_path))
|
||||||
|
|
||||||
# Append AI response to history
|
|
||||||
history.append({"role": "assistant", "content": response['message']['content']})
|
history.append({"role": "assistant", "content": response['message']['content']})
|
||||||
cl.user_session.set("history", history)
|
cl.user_session.set("history", history)
|
||||||
|
|
||||||
# Send final message
|
|
||||||
await cl.Message(content=response['message']['content'], elements=elements).send()
|
await cl.Message(content=response['message']['content'], elements=elements).send()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ services:
|
||||||
- ai-station-net
|
- ai-station-net
|
||||||
|
|
||||||
qdrant:
|
qdrant:
|
||||||
image: qdrant/qdrant:v1.0.0
|
image: qdrant/qdrant:latest
|
||||||
ports:
|
ports:
|
||||||
- "6333:6333"
|
- "6333:6333"
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue