UNPKG

flare-api

Version:

A modern, fast, and intuitive Node.js framework for building APIs

178 lines (177 loc) 6.84 kB
"use strict"; const tf = require("@tensorflow/tfjs-node"); const { Console } = require("console"); const fs = require('fs'); const path = require('path'); class FlareInterpreter { constructor() { this.model = null; this.patterns = { entity: { en: /Entity\s+(\w+)\s+with\s+Fields:\s+((?:\w+\s+\w+(?:,\s*)?)+)/i, es: /Entidad\s+(\w+)\s+con\s+Campos:\s+((?:\w+\s+\w+(?:,\s*)?)+)/i }, relationship: { en: /Relationship\s+(one-to-many|many-to-many|one-to-one|many-to-one)\s+between\s+(\w+)\s+and\s+(\w+)/i, es: /Relación\s+(uno-a-muchos|muchos-a-muchos|uno-a-uno|muchos-a-uno)\s+entre\s+(\w+)\s+y\s+(\w+)/i }, association: { en: /Associate\s+(\w+)\s+with\s+Fields:\s+((?:\w+\s+\w+(?:,\s*)?)+)/gi, es: /Asociar\s+(\w+)\s+con\s+Campos:\s+((?:\w+\s+\w+(?:,\s*)?)+)/gi } }; this.relationshipMap = { 'uno-a-muchos': 'one-to-many', 'muchos-a-muchos': 'many-to-many', 'uno-a-uno': 'one-to-one', 'muchos-a-uno': 'many-to-one' }; } async loadModel() { const modelPath = `file://${path.resolve(__dirname, 'model/model.json')}`; this.model = await tf.loadLayersModel(modelPath); console.log('Modelo cargado exitosamente'); } textToTensor(text) { const words = text.split(" "); const numbers = words.map(word => word.length); let tensor = tf.tensor1d(numbers, 'float32'); const requiredLength = 20; const currentLength = tensor.shape[0]; if (currentLength < requiredLength) { const padding = requiredLength - currentLength; tensor = tensor.pad([[0, padding]]); } else if (currentLength > requiredLength) { tensor = tensor.slice(0, requiredLength); } return tensor; } detectLanguage(text) { return text.match(/Entity|Relationship|Associate/i) ? 'en' : 'es'; } parseFields(fieldsText) { const fields = {}; fieldsText.split(',').forEach(field => { const [name, type] = field.trim().split(/\s+/); if (name && type) { // Verificar que ambos estén definidos fields[name] = type; } else { console.warn(`Error parsing field: ${field}`); } }); return fields; } parseAssociations(text, language) { const associations = []; const pattern = this.patterns.association[language]; let match; while ((match = pattern.exec(text)) !== null) { // Parse fields but exclude the 'Associate' keyword if it appears const fields = this.parseFields(match[2]); // Verificar y remover campos que no deberían estar en 'fields' delete fields['Associate']; associations.push({ name: match[1], fields: fields }); } return associations; } parseRelationship(text, language) { const pattern = this.patterns.relationship[language]; const match = text.match(pattern); if (!match) return null; let relationshipType = match[1]; // Normalizar tipo de relación a inglés si está en español if (this.relationshipMap[relationshipType]) { relationshipType = this.relationshipMap[relationshipType]; } return { source: match[2], target: match[3], relationshipType }; } parseEntity(text, language) { const pattern = this.patterns.entity[language]; const match = text.match(pattern); if (!match) return null; return { name: match[1], fields: this.parseFields(match[2]) }; } async interpretText(text) { if (!this.model) await this.loadModel(); // ML prediction const inputTensor = this.textToTensor(text).reshape([1, 20]); const prediction = this.model.predict(inputTensor); const predictedLabel = prediction.argMax(-1).dataSync()[0]; const commandsMap = { 0: { action: "crear", type: "api" }, 1: { action: "crear", type: "entidad" }, 2: { action: "crear", type: "controlador" }, 3: { action: "crear", type: "backoffice" }, 4: { action: "integrar", type: "autenticación" }, 5: { action: "create", type: "api" }, 6: { action: "create", type: "entity" }, 7: { action: "create", type: "controller" }, 8: { action: "create", type: "backoffice" }, 9: { action: "integrate", type: "authentication" } }; const result = commandsMap[predictedLabel]; const language = this.detectLanguage(text); // Parse entity or relationship let entityData = this.parseEntity(text, language); const relationship = this.parseRelationship(text, language); const associations = this.parseAssociations(text, language); // Si es una relación y no hay entidad definida, usar la fuente como entidad if (!entityData && relationship) { entityData = { name: relationship.source, fields: {} }; } if (entityData && entityData.fields) { delete entityData.fields.Associate; } // Construir resultado final const finalResult = { ...result, entityName: entityData ? entityData.name : null, fields: entityData ? entityData.fields : {}, relatedEntities: [] }; // Agregar asociaciones como entidades relacionadas if (associations.length > 0) { associations.forEach(assoc => { // Remover 'Associate' del objeto de fields si aparece if (assoc.fields['Associate']) { delete assoc.fields['Associate']; } finalResult.relatedEntities.push(assoc); }); } // Agregar relación si existe if (relationship) { finalResult.relatedEntities.push({ name: relationship.target, relationshipType: relationship.relationshipType }); } console.log(" este me interesa : ", finalResult); // Agregar la entidad "Team" si fue identificada en las asociaciones return finalResult; } } module.exports = { interpretText: async (text) => { const interpreter = new FlareInterpreter(); return await interpreter.interpretText(text); } };