flare-api
Version:
A modern, fast, and intuitive Node.js framework for building APIs
178 lines (177 loc) • 6.84 kB
JavaScript
;
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);
}
};