PageSourceSearch

https://datastat.ai/index.js

js datastat.ai collected 2026-10-05 15:31:33 UTC 8,856 bytes, 218 lines download raw bytes

1require('dotenv').config();
2const express = require('express');
3const nodemailer = require('nodemailer');
4
5const app = express();
6const port = process.env.PORT || 5500;
7
8// Parse JSON bodies
9app.use(express.json());
10app.use((req, res, next) => {
11  res.header('Access-Control-Allow-Origin', '*');
12  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
13  res.header('Access-Control-Allow-Headers', 'Content-Type');
14  next();
15});
16
17
18// -------------------- SEND SUPPORT TICKET --------------------
19app.post('/support_ai.html/send-data', (req, res) => {
20  const { username, phoneNumber, chatHistory, whatsapp } = req.body;
21
22  if (!username || !phoneNumber || typeof whatsapp !== 'boolean') {
23    return res.status(400).json({
24      message: 'Missing or invalid fields: username, phoneNumber and whatsapp (true/false) are required.'
25    });
26  }
27
28  const transporter = nodemailer.createTransport({
29    host: process.env.SMTP_HOST,
30    port: Number(process.env.SMTP_PORT),
31    secure: true,
32    auth: {
33      user: process.env.EMAIL_USER,
34      pass: process.env.EMAIL_PASS,
35    },
36  });
37
38  const contactPref = whatsapp ? 'WhatsApp' : 'Telefono';
39
40const mailOptions = {
41  from: process.env.EMAIL_USER,
42  to: process.env.RECEIVER_EMAIL,
43  subject: `📩 Nuova Richiesta di Supporto per: ${username}`,
44  html: `
45    <h2>📩 Nuova Richiesta di Supporto</h2>
46    <p><strong>👤 Nome Utente:</strong> ${username}</p>
47    <p><strong>📞 Telefono:</strong> ${phoneNumber}</p>
48    <p><strong>💬 Preferenza contatto:</strong> ${contactPref}</p>
49
50    <h3>💬 Storico Chat:</h3>
51<div style="font-family: Arial, sans-serif; max-width:600px;">
52  ${chatHistory
53    ? chatHistory
54        .split(/\r?\n/) // suddivide per linee
55        .map(line => {
56          let isUser = line.toLowerCase().includes('user:');
57          let isAssistant = line.toLowerCase().includes('assistant:');
58
59          let bgColor = isUser ? '#e3f2fd' : isAssistant ? '#f1f8e9' : '#fff3e0';
60          let borderColor = isUser ? '#2196f3' : isAssistant ? '#4caf50' : '#ff9800';
61          let icon = isUser ? '👤' : isAssistant ? '🤖' : '⚙️';
62          let label = isUser ? 'Utente' : isAssistant ? 'Assistente' : 'Sistema';
63
64          // rimuove il prefisso "user:" o "assistant:" dalla linea
65          let messageText = line.replace(/^user:\s*/i, '').replace(/^assistant:\s*/i, '');
66
67          return `
68            <div style="margin:6px 0; padding:8px; background:${bgColor}; border-left:4px solid ${borderColor}; border-radius:6px;">
69              <div style="display:flex; align-items:center; margin-bottom:4px;">
70                <strong style="color:${isUser ? '#1976d2' : '#388e3c'}">${icon} ${label}</strong>
71              </div>
72              <p style="margin:0; font-size:14px; line-height:1.4; color:#333;">${messageText}</p>
73            </div>
74          `;
75        })
76        .join('')
77    : '<p>Nessuno storico disponibile</p>'
78  }
79</div>
80
81    <hr style="margin:20px 0;border:none;border-top:1px solid #ddd;">
82    <p style="color:#666;font-size:12px;text-align:center;">Email generata automaticamente dal sistema TonyAI</p>
83  `,
84};
85  transporter.sendMail(mailOptions, (err, info) => {
86    if (err) {
87      console.error('❌ Error sending support ticket email:', err);
88      return res.status(500).json({ message: 'Error sending email', err });
89    }
90    console.log('✅ Support ticket email sent:', info.response);
91    res.json({ message: 'Email sent successfully', info });
92  });
93});
94
95
96// -------------------- SEND CHAT TRANSCRIPT --------------------
97function getBrowserName(userAgent) {
98  if (!userAgent) return 'Non disponibile';
99  
100  if (userAgent.includes('Edg/')) return 'Microsoft Edge';
101  if (userAgent.includes('Chrome/') && !userAgent.includes('Edg/')) return 'Google Chrome';
102  if (userAgent.includes('Firefox/')) return 'Mozilla Firefox';
103  if (userAgent.includes('Safari/') && !userAgent.includes('Chrome/')) return 'Safari';
104  if (userAgent.includes('Opera/') || userAgent.includes('OPR/')) return 'Opera';
105  if (userAgent.includes('Brave/')) return 'Brave';
106  
107  return 'Browser Sconosciuto';
108}
109
110
111const transporterTony = nodemailer.createTransport({
112  host: process.env.SMTP_HOST,
113  port: Number(process.env.SMTP_PORT),
114  secure: true,
115  auth: {
116    user: process.env.EMAIL_USER,
117    pass: process.env.EMAIL_PASS,
118  },
119});
120
121app.post('/support_ai.html/send-chat-transcript', async (req, res) => {
122  console.log('🔵 Endpoint hit!'); // Add this first
123  console.log('📦 Request body:', JSON.stringify(req.body, null, 2)); // Log full body
124  
125  try {
126    const { transcript, timestamp, BrowserType, endReason, messagesCount } = req.body;
127
128    console.log('📊 Parsed data:', { 
129      transcriptLength: transcript?.length, 
130      timestamp, 
131      BrowserType, 
132      endReason, 
133      messagesCount 
134    });
135
136    if (!transcript || !Array.isArray(transcript) || transcript.length === 0) {
137      console.log('❌ Validation failed: transcript invalid');
138      return res.status(400).json({ success: false, error: 'Transcript vuoto o non valido' });
139    }
140
141    const browserName = getBrowserName(BrowserType);
142    console.log('🌐 Browser detected:', browserName);
143
144    const htmlContent = `
145      <h2>🤖 Nuova Conversazione TonyAI</h2>
146      <div style="background: #f5f5f5; padding: 15px; border-radius: 8px; margin: 10px 0;">
147        <p><strong>📅 Data:</strong> ${new Date(timestamp).toLocaleString('it-IT')}</p>
148        <p><strong>🌐 Browser:</strong> ${browserName || 'Non disponibile'}</p>
149        <p><strong>📊 Numero messaggi:</strong> ${messagesCount || transcript.length}</p>
150        <p><strong>🔚 Motivo chiusura:</strong> ${endReason || 'Non specificato'}</p>
151      </div>
152
153      <h3>💬 Conversazione:</h3>
154      <div style="font-family: Arial, sans-serif; max-width: 600px;">
155        ${transcript.map(msg => {
156          const messageText = msg.message || msg.content || msg.text || 'Messaggio non disponibile';
157          const messageType = msg.type === 'assistant' ? 'assistant' : 'user';
158          const bgColor = messageType === 'user' ? '#e3f2fd' : '#f1f8e9';
159          const borderColor = messageType === 'user' ? '#2196f3' : '#4caf50';
160          const textColor = messageType === 'user' ? '#1976d2' : '#388e3c';
161          const icon = messageType === 'user' ? '👤' : '🤖';
162          const label = messageType === 'user' ? 'Utente' : 'Assistente';
163          const timestampMsg = msg.timestamp || timestamp;
164          return `
165            <div style="margin:15px 0; padding:15px; background:${bgColor}; border-radius:8px; border-left:4px solid ${borderColor};">
166              <div style="display:flex; align-items:center; margin-bottom:8px;">
167                <strong style="color:${textColor}; font-size:16px;">${icon} ${label}</strong>
168                <small style="color:#666; margin-left:auto; font-size:12px;">${new Date(timestampMsg).toLocaleString('it-IT')}</small>
169              </div>
170              <p style="margin:0; font-size:14px; line-height:1.4; color:#333;">${messageText}</p>
171            </div>
172          `;
173        }).join('')}
174      </div>
175
176      <hr style="margin:30px 0; border: none; border-top: 1px solid #ddd;">
177      <p style="color:#666; font-size:12px; text-align: center;">
178        Email generata automaticamente dal sistema TonyAI
179      </p>
180    `;
181
182    console.log('📧 Attempting to send email...');
183    const info = await transporterTony.sendMail({
184      from: process.env.EMAIL_USER,
185      to: process.env.RECEIVER_EMAIL,
186      subject: `💬 Conversazione TonyAI - ${new Date(timestamp).toLocaleString('it-IT')}`,
187      html: htmlContent,
188    });
189
190    console.log('✅ Email sent successfully:', info.messageId);
191    res.json({ success: true, messageId: info.messageId });
192
193  } catch (error) {
194    console.error('💥 Error sending transcript:', error);
195    res.status(500).json({ success: false, error: error.message });
196  }
197});
198
199// -------------------- HEARTBEAT --------------------
200app.post('/support_ai.html/heartbeat', (req, res) => {
201  res.json({ status: 'ok', timestamp: Date.now() });
202});
203
204// Serve static files
205app.use(express.static(__dirname));
206
207// Error handling middleware
208app.use((err, req, res, next) => {
209  console.error('Unhandled error:', err);
210  res.status(500).json({ success: false, error: 'Internal server error' });
211});
212
213// Start server
214app.listen(port, () => {
215  console.log(`🚀 Server running at http://localhost:${port}/`);
216  console.log(`📧 Endpoint ticket: http://localhost:${port}/support_ai.html/send-data`);
217  console.log(`📧 Endpoint chat transcript: http://localhost:${port}/support_ai.html/send-chat-transcript`);
218});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.