Descubre Q&A generado por OPENAI 01

Descubre preguntas públicas respondidas por OPENAI01

OpenAI 01 Preview

Mejoras en server6.js

// server6.js require('dotenv').config({ path: './src/.env' }); const express = require('express'); const pino = require('pino'); const cors = require('cors'); const http = require('http'); const socketIo = require('socket.io'); const bodyParser = require('body-parser'); const mysql = require('mysql'); const axios = require('axios'); const { promisify } = require('util'); const path = require('path'); const fs = require('fs'); const { parse } = require('json2csv'); // Para exportar datos a CSV const chalk = require('chalk'); const app = express(); const port = 3007; // Configuración del logger const logger = pino({ level: 'debug' }); // Configuración de CORS y Body Parser app.use(cors({ origin: 'http://localhost:3000' })); app.use(express.json()); app.use(bodyParser.json({ limit: '50mb' })); app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' })); // Configuración de la base de datos MySQL const dbConfig = { host: process.env.DB_IP, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: 'neox' }; const connection = mysql.createConnection(dbConfig); const query = promisify(connection.query).bind(connection); connection.connect(async (err) => { if (err) { console.error(chalk.red.bold('Error al conectar a la base de datos:'), err.code, err.fatal); return; } console.log(chalk.green.bold('Conectado a la base de datos')); // Crear base de datos si no existe const createDatabaseQuery = "CREATE DATABASE IF NOT EXISTS neox;"; connection.query(createDatabaseQuery, (err) => { if (err) { console.error(chalk.red.bold('Error al crear la base de datos "neox":'), err.message); return; } console.log(chalk.green.bold('Base de datos "neox" asegurada o ya existente')); connection.changeUser({ database: 'neox' }, (err) => { if (err) { console.error(chalk.red.bold('Error al cambiar a la base de datos "neox":'), err.message); return; } // Crear tabla perfiles const createPerfilesTableQuery = ` CREATE TABLE IF NOT EXISTS perfiles ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(255) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; `; connection.query(createPerfilesTableQuery, (err) => { if (err) { console.error(chalk.red.bold('Error al crear la tabla "perfiles":'), err.message); return; } console.log(chalk.green.bold('Tabla "perfiles" asegurada o ya existente')); // Crear tabla contextos const createContextosTableQuery = ` CREATE TABLE IF NOT EXISTS contextos ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(255) NOT NULL, descripcion TEXT NOT NULL, perfil_id INT NOT NULL, PRIMARY KEY (id), FOREIGN KEY (perfil_id) REFERENCES perfiles(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; `; connection.query(createContextosTableQuery, (err) => { if (err) { console.error(chalk.red.bold('Error al crear la tabla "contextos":'), err.message); return; } console.log(chalk.green.bold('Tabla "contextos" asegurada o ya existente')); // Crear tabla palabras_clave const createPalabrasClaveTableQuery = ` CREATE TABLE IF NOT EXISTS palabras_clave ( id INT NOT NULL AUTO_INCREMENT, palabra VARCHAR(255) NOT NULL, contexto_id INT NOT NULL, PRIMARY KEY (id), FOREIGN KEY (contexto_id) REFERENCES contextos(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; `; connection.query(createPalabrasClaveTableQuery, (err) => { if (err) { console.error(chalk.red.bold('Error al crear la tabla "palabras_clave":'), err.message); return; } console.log(chalk.green.bold('Tabla "palabras_clave" asegurada o ya existente')); }); }); }); }); }); }); // Configuración de Socket.io (si es necesario) const server = http.createServer(app); const io = socketIo(server, { cors: { origin: 'http://localhost:3000', methods: ['GET', 'POST'] } }); // Estado global de IA let isIaActive = false; let iaProfile = ''; // Endpoint: Obtener perfiles de IA app.get('/api/profiles', async (req, res) => { try { const profiles = await query('SELECT * FROM perfiles'); res.status(200).json(profiles); } catch (error) { console.error(chalk.red.bold('Error al obtener perfiles:'), error.message); res.status(500).send('Error al obtener perfiles'); } }); // Endpoint: Crear un nuevo perfil de IA app.post('/api/profiles', (req, res) => { const { nombre } = req.body; if (!nombre) { return res.status(400).send('El nombre del perfil es requerido'); } const queryStr = 'INSERT INTO perfiles (nombre) VALUES (?)'; connection.query(queryStr, [nombre], (err, results) => { if (err) { console.error('Error al crear perfil:', err.message); res.status(500).send('Error al crear perfil'); } else { res.status(201).send('Perfil creado exitosamente'); } }); }); // Endpoint: Obtener contextos y palabras clave para un perfil de IA específico app.get('/api/contextos/:iaProfile', async (req, res) => { const { iaProfile } = req.params; if (!iaProfile) { return res.status(400).send('El ID del perfil de IA es requerido'); } try { const contextos = await query('SELECT * FROM contextos WHERE perfil_id = ?', [iaProfile]); const palabrasClave = await query( 'SELECT * FROM palabras_clave WHERE contexto_id IN (SELECT id FROM contextos WHERE perfil_id = ?)', [iaProfile] ); res.status(200).json({ contextos, palabrasClave }); } catch (error) { console.error('Error al obtener contextos y palabras clave:', error.message); res.status(500).send('Error al obtener contextos y palabras clave'); } }); // Endpoint: Alternar estado de la IA app.post('/api/toggle-ia', (req, res) => { const { isIaActive: newState, iaProfile: newProfile } = req.body; if (typeof newState !== 'boolean' || !newProfile) { return res.status(400).send('Datos inválidos: se requiere "isIaActive" (boolean) y "iaProfile" (string)'); } isIaActive = newState; iaProfile = newProfile; console.log(`Estado de IA actualizado: isIaActive=${isIaActive}, iaProfile=${iaProfile}`); res.status(200).send('Estado de IA actualizado'); }); // Endpoint: Obtener historial de mensajes de un contacto específico app.get('/messages/:contactId', async (req, res) => { const { contactId } = req.params; if (!contactId) { return res.status(400).send('El ID del contacto es requerido'); } try { const messages = await query( 'SELECT * FROM neowhatsapp WHERE chatid = ? ORDER BY timestamp DESC', [contactId] ); // Formatear los mensajes según lo esperado por el frontend const formattedMessages = messages.map(msg => ({ fromMe: msg.tipo === 'enviado', message: msg.mensaje, timestamp: msg.timestamp })); res.status(200).json(formattedMessages); } catch (error) { console.error(chalk.red.bold('Error al obtener mensajes:'), error.message); res.status(500).send({ message: 'Error fetching messages' }); } }); // Endpoint: Generar un resumen de la conversación app.post('/summarize', async (req, res) => { const { text } = req.body; if (!text) { return res.status(400).send({ error: 'El texto para resumir es requerido' }); } try { const response = await axios.post('https://api.openai.com/v1/chat/completions', { model: "gpt-4", messages: [ { role: "system", content: "Eres un especialista en marketing e inteligencia de negocios con habilidades increíbles para entender sentimientos y dinámicas conductivas." }, { role: "user", content: `Resúmeme en un análisis de sentimientos y conductivo por puntos: ${text}` } ], max_tokens: 150, temperature: 0.7 }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.API_KEY}` } }); const summary = response.data.choices[0].message.content.trim(); res.json({ summary }); } catch (error) { console.error('Error generating summary:', error); res.status(500).json({ error: 'Error generating summary' }); } }); // Endpoint: Analizar una pregunta basada en la conversación app.post('/api/analyze', async (req, res) => { const { question, text, contextos, palabrasClave } = req.body; if (!question || !text || !contextos || !palabrasClave) { return res.status(400).send({ error: 'Faltan datos necesarios: "question", "text", "contextos", "palabrasClave"' }); } // Construir el prompt para OpenAI let prompt = `Pregunta: ${question}\n\nTexto de la conversación:\n${text}\n\nContextos relevantes:\n`; contextos.forEach(contexto => { prompt += `${contexto.descripcion}\n`; }); prompt += `\nPalabras clave relevantes:\n`; palabrasClave.forEach(palabra => { prompt += `${palabra.palabra}\n`; }); try { const response = await axios.post('https://api.openai.com/v1/chat/completions', { model: "gpt-4", messages: [ { role: "system", content: "Eres un asistente útil." }, { role: "user", content: prompt } ], max_tokens: 150, temperature: 0.7 }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.API_KEY}` } }); const iaResponse = response.data.choices[0].message.content.trim(); res.json({ result: iaResponse }); } catch (error) { console.error('Error analyzing question:', error); res.status(500).json({ error: 'Error analyzing question' }); } }); // Endpoint: Exportar datos a CSV app.post('/export-join-result', (req, res) => { try { const data = req.body.data; if (!data || data.length === 0) { return res.status(400).json({ error: 'No data provided' }); } const fields = Object.keys(data[0]); const opts = { fields }; const csv = parse(data, opts); const fileName = `export_${Date.now()}.csv`; const filePath = path.join('public', fileName); fs.writeFileSync(filePath, csv); res.status(200).json({ filePath: `/${fileName}` }); } catch (err) { console.error('Error exporting data:', err); res.status(500).json({ error: 'Error exporting data' }); } }); // Servir archivos CSV exportados app.use('/export_*.csv', express.static(path.join(__dirname, 'public'))); // Configuración de Socket.io (si es necesario) io.on('connection', (socket) => { console.log(chalk.green.bold('Client connected')); socket.on('disconnect', () => { console.log(chalk.green.bold('Client disconnected')); }); }); // Iniciar el servidor server.listen(port, () => { console.log(chalk.green.bold(`Servidor server6.js corriendo en el puerto ${port}`)); });

Creado por Leonardo Sardin y OPENAI01
OpenAI 01 Preview

Mejoras en NeoWhatsappMenu

// NeoWhatsappMenu.js import React, { useState, useEffect, useCallback } from 'react'; import { Box, Typography, Switch, FormControl, InputLabel, Select, MenuItem, TextField, Button, Paper, CircularProgress } from '@mui/material'; import axios from 'axios'; const API_BASE_URL = 'http://localhost:3007/api'; // Nuevo puerto const NeoWhatsappMenu = ({ selectedContacts, allMessages, onAnalyzeMessages, isIaActive, setIsIaActive }) => { const [iaProfile, setIaProfile] = useState(''); const [profiles, setProfiles] = useState([]); const [contextos, setContextos] = useState([]); const [palabrasClave, setPalabrasClave] = useState([]); const [question, setQuestion] = useState(''); const [analysisResult, setAnalysisResult] = useState(''); const [summary, setSummary] = useState(''); // Estados para manejo de carga y errores const [loadingProfiles, setLoadingProfiles] = useState(false); const [errorProfiles, setErrorProfiles] = useState(null); const [loadingContextos, setLoadingContextos] = useState(false); const [errorContextos, setErrorContextos] = useState(null); const [loadingAnalysis, setLoadingAnalysis] = useState(false); const [errorAnalysis, setErrorAnalysis] = useState(null); const [loadingSummary, setLoadingSummary] = useState(false); const [errorSummary, setErrorSummary] = useState(null); // Fetch profiles on component mount useEffect(() => { const fetchProfiles = async () => { setLoadingProfiles(true); setErrorProfiles(null); try { const response = await axios.get(`${API_BASE_URL}/profiles`); setProfiles(response.data); } catch (error) { console.error('Error fetching profiles:', error); setErrorProfiles('No se pudieron cargar los perfiles.'); } finally { setLoadingProfiles(false); } }; fetchProfiles(); }, []); // Fetch contextos and palabras clave when iaProfile changes useEffect(() => { if (iaProfile) { const fetchContextos = async () => { setLoadingContextos(true); setErrorContextos(null); try { const response = await axios.get(`${API_BASE_URL}/contextos/${iaProfile}`); setContextos(response.data.contextos); setPalabrasClave(response.data.palabrasClave); } catch (error) { console.error('Error fetching contextos and palabras clave:', error); setErrorContextos('No se pudieron cargar los contextos y palabras clave.'); } finally { setLoadingContextos(false); } }; fetchContextos(); } else { setContextos([]); setPalabrasClave([]); } }, [iaProfile]); // Toggle IA activation const handleIaToggle = async () => { const newState = !isIaActive; setIsIaActive(newState); try { await axios.post(`${API_BASE_URL}/toggle-ia`, { isIaActive: newState, iaProfile }); } catch (error) { console.error('Error toggling IA state:', error); // Opcional: manejar el error de manera más amigable para el usuario } }; // Handle IA profile change const handleIaProfileChange = async (event) => { const selectedProfile = event.target.value; setIaProfile(selectedProfile); onAnalyzeMessages(selectedProfile); try { await axios.post(`${API_BASE_URL}/toggle-ia`, { isIaActive, iaProfile: selectedProfile }); } catch (error) { console.error('Error updating IA profile:', error); // Opcional: manejar el error de manera más amigable para el usuario } }; // Handle question input change const handleQuestionChange = (event) => { setQuestion(event.target.value); }; // Fetch conversation history for a contact const fetchConversationHistory = useCallback(async (contactId) => { try { const response = await axios.get(`http://localhost:3007/messages/${contactId}`); // Endpoint sin /api return response.data.map(msg => msg.message).join('\n'); } catch (error) { console.error('Error fetching conversation history:', error); return ''; } }, []); // Generate summary of conversations const handleGenerateSummary = async () => { setLoadingSummary(true); setErrorSummary(null); const selectedMessages = selectedContacts.flatMap(contactId => allMessages[contactId] || []); const conversationText = selectedMessages.map(msg => msg.message).join('\n'); try { const response = await fetch('http://localhost:3007/summarize', { // Endpoint sin /api method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: conversationText }), }); const data = await response.json(); setSummary(data.summary); } catch (error) { console.error('Error generating summary:', error); setErrorSummary('Error al generar el resumen.'); } finally { setLoadingSummary(false); } }; // Ask a question based on conversation const handleAskQuestion = async () => { if (!question.trim()) { setAnalysisResult('Por favor, ingresa una pregunta válida.'); return; } setLoadingAnalysis(true); setErrorAnalysis(null); setAnalysisResult(''); const selectedMessages = selectedContacts.flatMap(contactId => allMessages[contactId] || []); const conversationText = selectedMessages.map(msg => msg.message).join('\n'); try { const histories = await Promise.all(selectedContacts.map(fetchConversationHistory)); const combinedHistory = histories.join('\n'); const response = await axios.post(`${API_BASE_URL}/analyze`, { // Endpoint con /api question, text: combinedHistory + '\n' + conversationText, contextos, palabrasClave, }); setAnalysisResult(response.data.result); } catch (error) { console.error('Error analyzing question:', error); setAnalysisResult('Error al analizar la pregunta.'); setErrorAnalysis('Error al analizar la pregunta.'); } finally { setLoadingAnalysis(false); } }; return ( <Box sx={{ width: '600px', height: '100vh', display: 'flex', flexDirection: 'column', bgcolor: 'background.paper', overflow: 'auto' }} > <Typography variant="h6" sx={{ p: 2 }}>Funcionalidades Adicionales</Typography> {/* IA Activation and Profile Selection */} <Paper sx={{ m: 2, p: 2 }}> <Box display="flex" alignItems="center"> <Typography variant="body1">IA Activa</Typography> <Switch checked={isIaActive} onChange={handleIaToggle} inputProps={{ 'aria-label': 'Activar IA' }} /> </Box> {/* Profiles Loading and Error Handling */} {loadingProfiles ? ( <Box display="flex" justifyContent="center" sx={{ mt: 2 }}> <CircularProgress /> </Box> ) : errorProfiles ? ( <Typography color="error" sx={{ mt: 2 }}>{errorProfiles}</Typography> ) : ( <FormControl fullWidth sx={{ mt: 2 }} disabled={!isIaActive}> <InputLabel id="ia-profile-label">Perfil de IA</InputLabel> <Select labelId="ia-profile-label" value={iaProfile} label="Perfil de IA" onChange={handleIaProfileChange} > {profiles.map(profile => ( <MenuItem key={profile.id} value={profile.id}>{profile.nombre}</MenuItem> ))} </Select> </FormControl> )} {/* Contextos Loading and Error Handling */} {iaProfile && ( <> {loadingContextos ? ( <Box display="flex" justifyContent="center" sx={{ mt: 2 }}> <CircularProgress size={24} /> </Box> ) : errorContextos ? ( <Typography color="error" sx={{ mt: 2 }}>{errorContextos}</Typography> ) : null} </> )} {/* Question Input */} <TextField label="Pregunta para el análisis" variant="outlined" fullWidth value={question} onChange={handleQuestionChange} disabled={!isIaActive} sx={{ mt: 2 }} inputProps={{ 'aria-label': 'Pregunta para el análisis' }} /> {/* Ask Question Button */} <Button variant="contained" color="primary" onClick={handleAskQuestion} sx={{ mt: 2 }} disabled={!isIaActive || loadingAnalysis} > {loadingAnalysis ? 'Analizando...' : 'Realizar Pregunta'} </Button> {/* Analysis Result */} {analysisResult && ( <Paper sx={{ mt: 2, p: 2 }}> <Typography variant="body1">Resultado del Análisis</Typography> <Typography variant="body2" sx={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}> {analysisResult} </Typography> </Paper> )} {/* Error Analysis */} {errorAnalysis && ( <Typography color="error" sx={{ mt: 2 }}>{errorAnalysis}</Typography> )} </Paper> {/* Sentiment Analysis and Summary */} <Paper sx={{ m: 2, p: 2 }}> <Typography variant="h6">Análisis de sentimientos</Typography> {/* Generate Summary Button */} <Button variant="contained" color="primary" onClick={handleGenerateSummary} sx={{ mt: 2 }} disabled={loadingSummary} > {loadingSummary ? 'Generando...' : 'Generar análisis'} </Button> {/* Summary Result */} {summary && ( <Paper sx={{ mt: 2, p: 2 }}> <Typography variant="body1">Resumen:</Typography> <Typography variant="body2" sx={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}> {summary} </Typography> </Paper> )} {/* Error Summary */} {errorSummary && ( <Typography color="error" sx={{ mt: 2 }}>{errorSummary}</Typography> )} </Paper> </Box> ); }; export default NeoWhatsappMenu;

Creado por Leonardo Sardin y OPENAI01