- Iniziato a scrivere la CHATBOT...

This commit is contained in:
Surya Paolo
2025-08-09 00:48:50 +02:00
parent 32210bb96a
commit e3db42dcbc
5 changed files with 218 additions and 94 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -21,14 +21,13 @@ const globalTables = require('../tools/globalTables');
const { ObjectId } = require('mongodb');
const OpenAI = require("openai");
const OpenAI = require('openai');
const { PassThrough } = require('stream');
const { spawn } = require('child_process');
router.post('/getlist', authenticate_noerror, async function (req, res, next) {
try {
let idapp = req.body.idapp;
@@ -36,26 +35,23 @@ router.post('/getlist', authenticate_noerror, async function (req, res, next) {
return res.send({
code: server_constants.RIS_CODE_OK,
queryAIList
queryAIList,
});
} catch (e) {
console.error('/getlist', e);
}
return null;
});
async function getDeepSeekResponse(prompt, options) {
try {
const deepseek = new OpenAI({
baseURL: 'https://api.deepseek.com/v1',
apiKey: process.env.DS_API_KEY,
defaultHeaders: {
'Content-Type': 'application/json'
}
'Content-Type': 'application/json',
},
});
if (!options.withexplain) {
@@ -66,10 +62,10 @@ async function getDeepSeekResponse(prompt, options) {
}
const completionStream = await deepseek.chat.completions.create({
model: options.model || "deepseek-chat",
model: options.model || 'deepseek-chat',
messages: [
{ role: "system", content: options?.contestsystem || "" },
{ role: "user", content: prompt }
{ role: 'system', content: options?.contestsystem || '' },
{ role: 'user', content: prompt },
],
temperature: options?.temp || 0.3,
max_tokens: options?.max_tokens || 1000,
@@ -101,72 +97,147 @@ async function getDeepSeekResponse(prompt, options) {
}
router.post('/ds', authenticate, async (req, res) => {
const { prompt, options } = req.body;
const isstream = (options && options?.stream)
const isollama = options.model.startsWith('gemma3');
if (isstream) {
// Se lo streaming è abilitato, restituiamo un flusso di dati
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
if (isollama) {
// Endpoint per generare una risposta dal modello Ollama
const { prompt } = req.body;
// const model = "phi:3.8b-mini-4k"; // Modello predefinito
const model = options.model;
if (!prompt) {
return res.status(400).json({ error: 'Il prompt è richiesto.' });
}
try {
// Ottieni il flusso di dati da DeepSeek
const completionStream = await getDeepSeekResponse(prompt, options);
for await (const chunk of completionStream) {
if (chunk.choices && chunk.choices[0]) {
const data = JSON.stringify({ choice: chunk.choices[0] });
res.write(`data: ${data}\n\n`);
try {
const msg = chunk.choices[0].delta.content;
if (msg) {
console.log(msg);
// await tools.sleep(10000)
}
} catch (e) {
console.error('Error: ' + e.message);
}
}
}
// Chiamata all'API di Ollama
const ollama = spawn('curl', [
'-X',
'POST',
'http://localhost:11434/api/generate',
'-H',
'Content-Type: application/json',
'-d',
JSON.stringify({
model: model,
prompt: prompt,
stream: false, // Imposta a true se vuoi una risposta in streaming
}),
]);
res.write('data: [DONE]\n\n');
res.end();
let data = '';
let error = '';
} catch (error) {
const errorstr = 'DeepSeek API Error:' + (error.response?.data || error.message)
console.error(errorstr);
// In caso di errore durante lo streaming, invia un messaggio di errore
const errorData = JSON.stringify({
code: server_constants.RIS_CODE_ERR,
error: errorstr,
ollama.stdout.on('data', (chunk) => {
data += chunk;
});
res.write(`data: ${errorData}\n\n`);
res.end();
ollama.stderr.on('data', (chunk) => {
error += chunk;
});
ollama.on('close', (code) => {
if (code !== 0) {
console.error(`Errore Ollama: ${error}`);
return res.status(500).json({ error: 'Errore nella generazione del modello.' });
}
try {
// Ollama restituisce una risposta JSON
const response = JSON.parse(data);
const risp = response?.error ? response?.error : response?.response;
//res.json({ response: response.response }); // Invia solo la risposta al frontend
if (response?.error) {
return res.send({
code: server_constants.RIS_CODE_ERR,
error: risp,
});
} else {
return res.send({
code: server_constants.RIS_CODE_OK,
choice: risp,
});
}
} catch (parseError) {
console.error('Errore nel parsing della risposta di Ollama:', parseError);
return res.send({
code: server_constants.RIS_CODE_ERR,
error: 'Errore nella risposta del modello.',
});
}
});
} catch (err) {
console.error(err);
return res.send({
code: server_constants.RIS_CODE_ERR,
error: 'Errore interno del server.',
});
}
} else {
try {
// Se lo streaming non è abilitato, restituisci la risposta completa
const choice = await getDeepSeekResponse(prompt, options);
const isstream = options && options?.stream;
return res.send({
code: server_constants.RIS_CODE_OK,
choice,
});
} catch (error) {
const errorstr = 'DeepSeek API Error:' + (error.response?.data || error.message)
console.error(errorstr);
if (isstream) {
// Se lo streaming è abilitato, restituiamo un flusso di dati
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// In caso di errore senza streaming, restituisci un errore standard
return res.send({
code: server_constants.RIS_CODE_ERR,
error: errorstr,
});
try {
// Ottieni il flusso di dati da DeepSeek
const completionStream = await getDeepSeekResponse(prompt, options);
for await (const chunk of completionStream) {
if (chunk.choices && chunk.choices[0]) {
const data = JSON.stringify({ choice: chunk.choices[0] });
res.write(`data: ${data}\n\n`);
try {
const msg = chunk.choices[0].delta.content;
if (msg) {
console.log(msg);
// await tools.sleep(10000)
}
} catch (e) {
console.error('Error: ' + e.message);
}
}
}
res.write('data: [DONE]\n\n');
res.end();
} catch (error) {
const errorstr = 'API Error:' + (error.response?.data || error.message);
console.error(errorstr);
// In caso di errore durante lo streaming, invia un messaggio di errore
const errorData = JSON.stringify({
code: server_constants.RIS_CODE_ERR,
error: errorstr,
});
res.write(`data: ${errorData}\n\n`);
res.end();
}
} else {
try {
// Se lo streaming non è abilitato, restituisci la risposta completa
const choice = await getDeepSeekResponse(prompt, options);
return res.send({
code: server_constants.RIS_CODE_OK,
choice,
});
} catch (error) {
const errorstr = 'API Error:' + (error.response?.data || error.message);
console.error(errorstr);
// In caso di errore senza streaming, restituisci un errore standard
return res.send({
code: server_constants.RIS_CODE_ERR,
error: errorstr,
});
}
}
}
});

View File

@@ -15,6 +15,8 @@ const Author = require('../models/author');
const tools = require('../tools/general');
const axios = require('axios');
router.post('/test-lungo', authenticate, (req, res) => {
const timeout = req.body.timeout;
@@ -453,4 +455,19 @@ router.post('/search-books', authenticate, async (req, res) => {
}
});
router.post('/chatbot', authenticate, async (req, res) => {
try {
const response = await axios.post('http://localhost:5005/webhooks/rest/webhook', {
sender: 'user',
message: req.body.payload.message,
});
res.json(response.data);
} catch (error) {
console.error(error);
res.status(500).send('Errore nella comunicazione con Rasa');
}
});
module.exports = router;

View File

@@ -11,6 +11,9 @@ const appTelegramDest = [tools.FREEPLANET, tools.FREEPLANET];
const appTeleg_BotOnGroup = [tools.IDAPP_BOTONGROUP];
const path = require('path');
const fs = require('fs');
//PIPPO
const printf = require('util').format;
@@ -31,8 +34,6 @@ const server_constants = require('../tools/server_constants');
// const {ListaIngresso} = require('../models/listaingresso');
const { MsgTemplate } = require('../models/msg_template');
const globalTables = require('../tools/globalTables');
const i18n = require('i18n');
let url = process.env.URL || 'https://<PUBLIC-URL>';
@@ -1386,6 +1387,8 @@ const MyTelegramBot = {
sendMsgFromSite: async function (idapp, user, params) {
try {
const globalTables = require('../tools/globalTables');
let ris = {
numrec: 0,
nummsgsent: 0,
@@ -3810,34 +3813,69 @@ class Telegram {
}
}
// Soluzione 3: Implementazione completa con gestione errori e tentativi multipli
async sendImageToTelegram(chatId, imageUrl, opt) {
try {
// Prima prova: invia direttamente l'URL
// Primo tentativo: invia direttamente l'URL
try {
return await this.bot.sendPhoto(chatId, imageUrl, opt);
} catch (error) {
console.log('Primo tentativo fallito, provo a convertire...');
}
// Seconda prova: scarica e converti in JPG
const response = await axios.get(imageUrl, { responseType: 'arraybuffer' });
const imageBuffer = Buffer.from(response.data);
const jpgBuffer = await sharp(imageBuffer).jpeg({ quality: 90 }).toBuffer();
console.log('imageUrl', imageUrl);
// Secondo tentativo: scarica e converte con sharp
try {
return await this.bot.sendPhoto(chatId, jpgBuffer, opt);
} catch (error) {
console.log('Secondo tentativo fallito, provo come documento...');
const response = await axios.get(imageUrl, { responseType: 'arraybuffer' });
const contentType = response.headers['content-type'];
const imageBuffer = Buffer.from(response.data);
if (!contentType.startsWith('image/')) {
console.warn('Non è un formato immagine:', contentType);
return await this.bot.sendDocument(chatId, imageBuffer, opt);
}
try {
const jpgBuffer = await sharp(imageBuffer).jpeg({ quality: 90 }).toBuffer();
return await this.bot.sendPhoto(chatId, jpgBuffer, opt);
} catch (err) {
console.warn('Sharp conversion failed:', err.message);
return await this.bot.sendDocument(chatId, imageBuffer, opt);
}
} catch (err) {
console.warn("Errore nel download dell'immagine, provo con file locale...");
}
// Ultima prova: invia come documento
return await this.bot.sendDocument(chatId, imageBuffer, opt);
} catch (error) {
console.error('Tutti i tentativi di invio sono falliti:', error);
// Terzo tentativo: accedi al file localmente
try {
if (!imageUrl.includes('/upload/')) {
throw new Error('URL non contiene "/upload/", impossibile determinare il path locale.');
}
let dirmain = '';
if (!tools.sulServer()) {
dirmain = server_constants.DIR_PUBLIC_LOCALE;
}
const relativePath = imageUrl.split('/upload/')[1]; // es. "profile/surya1977/mygoods/1_module.jpg"
const mydir = tools.getdirByIdApp(opt.idapp) + dirmain + server_constants.DIR_UPLOAD;
const localPath = path.join(mydir, relativePath);
console.log('Cerco il file localmente:', localPath);
const localBuffer = fs.readFileSync(localPath);
return await this.bot.sendDocument(chatId, localBuffer, opt);
} catch (err) {
console.error('Lettura file locale fallita:', err.message);
}
// Se tutto fallisce
console.error('Tutti i tentativi di invio sono falliti');
return false;
} catch (error) {
console.error('Errore generale:', error);
return false;
//throw error;
}
}
@@ -3919,7 +3957,7 @@ class Telegram {
}
opt.img = tools.fixUrl(opt.img, opt.idapp);
console.log('opt.img', opt.img);
risSendPhoto = await this.sendImageToTelegram(id, opt.img, { caption: text, ...form }).catch((e) => {
risSendPhoto = await this.sendImageToTelegram(id, opt.img, { caption: text, ...form, ...opt }).catch((e) => {
let blocked = false;
if (e.message.indexOf('Forbidden') > 0 || e.message.indexOf('chat not found') > 0) {
blocked = true;
@@ -4362,7 +4400,7 @@ if (true) {
// RISPOSTE ALLE CALLBACK (Bottoni)
let testo_notifica_di_risposta = ''
let testo_notifica_di_risposta = '';
try {
const myclTelegram = getclTelegBytoken(bot.token);
@@ -4612,8 +4650,7 @@ if (true) {
}
// CALLBACK DI RISPOSTA AL BOT
bot.answerCallbackQuery(callbackQuery.id, { text: testo_notifica_di_risposta } ) ;
bot.answerCallbackQuery(callbackQuery.id, { text: testo_notifica_di_risposta });
} catch (e) {
console.error('Error BOT callback_query', e);
}

View File

@@ -5777,8 +5777,7 @@ module.exports = {
try {
// let dir = this.getdirByIdApp(idapp) + dirmain + '/' + this.getDirUpload();
let dir = this.getdirByIdApp(idapp);
'/' + this.getDirUpload() + shared_consts.getDirectoryImgByTable(table, username) + dirmain;
let dir = this.getdirByIdApp(idapp) + '/' + this.getDirUpload() + shared_consts.getDirectoryImgByTable(table, username) + dirmain;
img = dir + img;
@@ -5790,7 +5789,7 @@ module.exports = {
if (!this.sulServer()) {
// Finta Immagine
img = 'https://riso.app/upload/profile/SoniaVioletFlame/myskills/1000133092.jpg';
// img = 'https://riso.app/upload/profile/SoniaVioletFlame/myskills/1000133092.jpg';
}
return img;
@@ -5835,15 +5834,15 @@ module.exports = {
},
fixUrl(myurl, idapp) {
if (!myurl.startsWith('http')) {
return this.getHostByIdApp(idapp) + myurl;
}
//if (!myurl.startsWith('http')) {
// return this.getHostByIdApp(idapp) + myurl;
//}
if (myurl.startsWith('http://127.0.0.1')) {
//myurl = myurl.replace('http://127.0.0.1:8084/', 'https://riso.app/')
// Se è in locale allora metti una foto finta...
myurl =
'https://images.unsplash.com/photo-1464047736614-af63643285bf?q=80&w=2874&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D';
// myurl =
// 'https://images.unsplash.com/photo-1464047736614-af63643285bf?q=80&w=2874&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D';
//myurl = myurl.replace('http://127.0.0.1', 'http://localhost')
}