From 729d4346d618979e2fc0141340b9f41f449def94 Mon Sep 17 00:00:00 2001 From: ppf30 Date: Fri, 28 Nov 2025 12:37:04 +0100 Subject: [PATCH 01/13] modelo subido en model --- model/group1-shard1of1.bin:Zone.Identifier | Bin 0 -> 25 bytes model/model.json:Zone.Identifier | Bin 0 -> 25 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 model/group1-shard1of1.bin:Zone.Identifier create mode 100644 model/model.json:Zone.Identifier diff --git a/model/group1-shard1of1.bin:Zone.Identifier b/model/group1-shard1of1.bin:Zone.Identifier new file mode 100644 index 0000000000000000000000000000000000000000..d6c1ec682968c796b9f5e9e080cc6f674b57c766 GIT binary patch literal 25 dcma!!%Fjy;DN4*MPD?F{<>dl#JyUFr831@K2xdl#JyUFr831@K2x Date: Fri, 28 Nov 2025 13:48:08 +0100 Subject: [PATCH 02/13] borrado --- model/group1-shard1of1.bin:Zone.Identifier | Bin 25 -> 0 bytes model/model.json:Zone.Identifier | Bin 25 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 model/group1-shard1of1.bin:Zone.Identifier delete mode 100644 model/model.json:Zone.Identifier diff --git a/model/group1-shard1of1.bin:Zone.Identifier b/model/group1-shard1of1.bin:Zone.Identifier deleted file mode 100644 index d6c1ec682968c796b9f5e9e080cc6f674b57c766..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25 dcma!!%Fjy;DN4*MPD?F{<>dl#JyUFr831@K2xdl#JyUFr831@K2x Date: Fri, 28 Nov 2025 15:24:02 +0100 Subject: [PATCH 03/13] s3 --- package.json | 6 +++--- server.js | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 7e709810..4c9f6328 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,11 @@ }, "author": "Iren Lorenzo Fonseca", "license": "ISC", - "bugs": { - }, + "bugs": {}, "dependencies": { "@tensorflow/tfjs": "^4.22.0", "@tensorflow/tfjs-backend-wasm": "^4.22.0", + "dotenv": "^17.2.3", "express": "^5.1.0" } -} \ No newline at end of file +} diff --git a/server.js b/server.js index 4d44675f..eac84d3c 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ // server.js // Entry point del servicio PREDICT +require("dotenv").config(); const express = require("express"); const path = require("path"); From 73538ed928d46efd67155c2c0a8c34ad2473e158 Mon Sep 17 00:00:00 2001 From: ppf30 Date: Fri, 28 Nov 2025 16:42:37 +0100 Subject: [PATCH 04/13] docker --- .dockerignore | 8 ++++++++ dockerfile | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 .dockerignore create mode 100644 dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..ed60f1f4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules +npm-debug.log +Dockerfile +docker-compose.yml +.vscode +.git +.gitignore +.env \ No newline at end of file diff --git a/dockerfile b/dockerfile new file mode 100644 index 00000000..8990ac6c --- /dev/null +++ b/dockerfile @@ -0,0 +1,26 @@ +# Imagen base con Node 22 +FROM node:22-slim + + +# Directorio de trabajo dentro del contenedor +WORKDIR /usr/src/app + + +# Copiamos primero manifiestos para cachear dependencias +COPY package*.json ./ + + +# Instalamos dependencias de producción +RUN npm ci --omit=dev + + +# Copiamos el resto del código (incluye /model) +COPY . . + + +# El servicio escucha en 3002 +EXPOSE 3002 + + +# Comando de arranque +CMD ["node", "server.js"] \ No newline at end of file From 71ed90c7d14ec1a3469bcf4841649d0ff24f7750 Mon Sep 17 00:00:00 2001 From: ppf30 Date: Wed, 10 Dec 2025 20:21:46 +0100 Subject: [PATCH 05/13] =?UTF-8?q?revisi=C3=B3n=20server.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server.js b/server.js index eac84d3c..16a175df 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,7 @@ require("dotenv").config(); const express = require("express"); const path = require("path"); +const mongoose = require("mongoose"); const predictRoutes = require("./routes/predictRoutes"); const { initModel } = require("./services/tfModelService"); @@ -20,6 +21,7 @@ app.use("/model", express.static(modelDir)); app.use("/", predictRoutes); // Arranque del servidor + carga del modelo +/* app.listen(PORT, async () => { const serverUrl = `http://localhost:${PORT}`; console.log(`[PREDICT] Servicio escuchando en ${serverUrl}`); @@ -31,3 +33,14 @@ app.listen(PORT, async () => { process.exit(1); } }); +*/ +// conectar a Mongo +mongoose + .connect(process.env.MONGO_URI) + .then(() => console.log("MongoDB Atlas conectado (ACQUIRE)")) + .catch((err) => { + console.error("Error Mongo:", err); + process.exit(1); + }); +app.use("/", acquireRoutes); +app.use(express.json()); From 58912c0a2b044eb92580d56d16c359a4bedda2f4 Mon Sep 17 00:00:00 2001 From: ppf30 Date: Fri, 12 Dec 2025 12:29:50 +0100 Subject: [PATCH 06/13] Subiendo todo From ca28fefc17fde2078104f05cb50ba5423ea9f9be Mon Sep 17 00:00:00 2001 From: ppf30 Date: Fri, 12 Dec 2025 12:56:02 +0100 Subject: [PATCH 07/13] =?UTF-8?q?completado=20sever.js=20con=20la=20conexi?= =?UTF-8?q?=C3=B3na=20mongoDB=20y=20al=20modelo=20predictivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/server.js b/server.js index 16a175df..f87007bf 100644 --- a/server.js +++ b/server.js @@ -3,6 +3,7 @@ require("dotenv").config(); const express = require("express"); +const app = express(); const path = require("path"); const mongoose = require("mongoose"); const predictRoutes = require("./routes/predictRoutes"); @@ -10,37 +11,36 @@ const { initModel } = require("./services/tfModelService"); const PORT = process.env.PORT || 3002; -const app = express(); + app.use(express.json()); // Servir la carpeta del modelo TFJS (model/model.json + pesos) const modelDir = path.resolve(__dirname, "model"); app.use("/model", express.static(modelDir)); -// Rutas del servicio PREDICT + +// conectar a Mongo +mongoose + .connect(process.env.MONGO_URI) + .then(() => console.log("MongoDB conectado (PREDICT)")) + .catch((err) => { + console.error("Error al conectar MongoDB:", err); + process.exit(1); + }); + app.use("/", predictRoutes); -// Arranque del servidor + carga del modelo -/* + app.listen(PORT, async () => { - const serverUrl = `http://localhost:${PORT}`; - console.log(`[PREDICT] Servicio escuchando en ${serverUrl}`); + const serverUrl = "http://localhost:${PORT}"; + console.log("PREDICT escuchando en ${serverUrl}"); try { + // Inicializa el modelo predictivo await initModel(serverUrl); + console.log(" Modelo predictivo cargado correctamente."); } catch (err) { - console.error("Error al inicializar modelo:", err); + console.error("Error al inicializar el modelo predictivo:", err); process.exit(1); } }); -*/ -// conectar a Mongo -mongoose - .connect(process.env.MONGO_URI) - .then(() => console.log("MongoDB Atlas conectado (ACQUIRE)")) - .catch((err) => { - console.error("Error Mongo:", err); - process.exit(1); - }); -app.use("/", acquireRoutes); -app.use(express.json()); From 2aae4ee730764718574f3f1902ad9996a96d98c6 Mon Sep 17 00:00:00 2001 From: ppf30 Date: Fri, 12 Dec 2025 16:58:02 +0100 Subject: [PATCH 08/13] =?UTF-8?q?correcci=C3=B3n=20problemas=20con=20mongo?= =?UTF-8?q?=20db.=20Ya=20funciona=20en=20postman?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/Prediction.js | 24 ++++++++++++++++++++++++ package.json | 5 ++++- server.js | 13 +++++++------ 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 model/Prediction.js diff --git a/model/Prediction.js b/model/Prediction.js new file mode 100644 index 00000000..314fb07d --- /dev/null +++ b/model/Prediction.js @@ -0,0 +1,24 @@ +'use strict' + +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const PredictionSchema = new Schema({ + source: String, + timestamp: { type: Date, default: Date.now }, // Cuándo se hizo + latencyMs: Number, // Cuánto tardó + features: [Number], // Los datos de entrada (array de números) + prediction: Number, + + featureCount: Number, + scalerVersion: String, + createdAt: { type: Date, default: Date.now }, + targetDate: Date, + dailyValues: [Number], // Valores diarios originales sin escalar + + // Metadatos de Kunna (alias, fechas usadas...) + + // El resultado (array de números) +}); + +module.exports = mongoose.model('Prediction', PredictionSchema); \ No newline at end of file diff --git a/package.json b/package.json index 4c9f6328..42a9fc1b 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ "@tensorflow/tfjs": "^4.22.0", "@tensorflow/tfjs-backend-wasm": "^4.22.0", "dotenv": "^17.2.3", - "express": "^5.1.0" + "express": "^5.1.0", + "mongodb": "^7.0.0", + "mongoose": "^9.0.1" } } + diff --git a/server.js b/server.js index f87007bf..f853a215 100644 --- a/server.js +++ b/server.js @@ -14,10 +14,6 @@ const PORT = process.env.PORT || 3002; app.use(express.json()); -// Servir la carpeta del modelo TFJS (model/model.json + pesos) -const modelDir = path.resolve(__dirname, "model"); -app.use("/model", express.static(modelDir)); - // conectar a Mongo mongoose @@ -28,12 +24,17 @@ mongoose process.exit(1); }); +// Servir la carpeta del modelo TFJS (model/model.json + pesos) +const modelDir = path.resolve(__dirname, "model"); +app.use("/model", express.static(modelDir)); + + app.use("/", predictRoutes); app.listen(PORT, async () => { - const serverUrl = "http://localhost:${PORT}"; - console.log("PREDICT escuchando en ${serverUrl}"); + const serverUrl = `http://localhost:${PORT}`; + console.log(`PREDICT escuchando en ${serverUrl}`); try { // Inicializa el modelo predictivo From 17beb328aa30b0cc88ad7f9ec07de4af6654b633 Mon Sep 17 00:00:00 2001 From: ppf30 Date: Wed, 17 Dec 2025 09:47:11 +0100 Subject: [PATCH 09/13] =?UTF-8?q?revisi=C3=B3n=20del=20c=C3=B3digo=20y=20c?= =?UTF-8?q?orrecci=C3=B3n=20de=20comentarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/Prediction.js | 13 ++++++------- services/tfModelService.js | 11 ++--------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/model/Prediction.js b/model/Prediction.js index 314fb07d..da618943 100644 --- a/model/Prediction.js +++ b/model/Prediction.js @@ -1,3 +1,4 @@ +//model/prediction.js 'use strict' const mongoose = require('mongoose'); @@ -5,20 +6,18 @@ const Schema = mongoose.Schema; const PredictionSchema = new Schema({ source: String, - timestamp: { type: Date, default: Date.now }, // Cuándo se hizo - latencyMs: Number, // Cuánto tardó - features: [Number], // Los datos de entrada (array de números) + timestamp: { type: Date, default: Date.now }, + latencyMs: Number, + features: [Number], prediction: Number, featureCount: Number, scalerVersion: String, createdAt: { type: Date, default: Date.now }, targetDate: Date, - dailyValues: [Number], // Valores diarios originales sin escalar + dailyValues: [Number], - // Metadatos de Kunna (alias, fechas usadas...) - - // El resultado (array de números) + }); module.exports = mongoose.model('Prediction', PredictionSchema); \ No newline at end of file diff --git a/services/tfModelService.js b/services/tfModelService.js index aff8b787..01af4168 100644 --- a/services/tfModelService.js +++ b/services/tfModelService.js @@ -34,10 +34,7 @@ function wasmFileDirUrl() { return pathToFileURL(distFsPath + path.sep).href; } -/** - * Inicializa backend WASM y carga el GraphModel - * serverUrl: ej. http://localhost:3002 - */ + async function initModel(serverUrl) { const wasmPath = wasmFileDirUrl(); wasmBackend.setWasmPaths(wasmPath); @@ -66,7 +63,6 @@ async function initModel(serverUrl) { throw new Error("No se ha podido detectar inputName/outputName/inputDim"); } - // Warm-up const Xwarm = tf.zeros([1, inputDim], "float32"); let out; if (typeof model.executeAsync === "function") { @@ -83,10 +79,7 @@ async function initModel(serverUrl) { console.log("[TF] Modelo listo."); } -/** - * Ejecuta el modelo con un vector de features - * Devuelve un escalar >= 0 - */ + async function predict(features) { if (!ready || !model) { throw new Error("Model not ready"); From 5e98b3b0075c5f1abcf4ec31fbf5d5761c309956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patricia=20P=C3=A9rez=20Ferre?= Date: Thu, 18 Dec 2025 21:19:47 +0100 Subject: [PATCH 10/13] Create README.md with project details and usage Added project documentation including usage instructions, repository links, and project structure. --- README.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..2bba374e --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# PREDICT + + +## Repositorios del proyecto +```bash +https://github.com/ppf30/acquire.git +``` +```bash +https://github.com/ppf30/orchestrator.git +``` +```bash +https://github.com/ppf30/predict.git +``` + + +## Uso Local + +```bash +# Iniciar el orquestador +node server.js +``` + +## Uso docker +Todo el proyecto está dockerizado, por lo tanto si queremos probarlo con contenedores debemos clonar los repositorios y con el ```docker-compose.yml``` en la carpeta, ejecutamos los siguientes comandos en la terminal: +```bash +docker-compose up -d --build +``` + +Al finalizar podemos eliminar los contenedores: +```bash +docker-compose down +``` +## Pruebas en Postman +GET http://localhost:3001/health + +GET http://localhost:3001/ready + +POST http://localhost:3001/predict +```bash +# Body +{ + "features": [1.315, 1.81, 1.27, 8, 0, 9, 30], + "meta": { + "source": "orchestrator", + "dataId": "6772c1f3e2a0b12345678901", + "featureCount": 7, + "scalerVersion": "v1", + "targetDate": "2025-11-26T22:00:00.000Z", + "dailyValues": [28.186, 27.809, 27.44], + "kunnaMeta": { + "alias": "6339651", + "name": "1d", + "daysUsed": ["2025-11-25", "2025-11-24", "2025-11-23"] + }, + "fetchMeta": { + "timeStart": "2025-11-22T18:43:10.000Z", + "timeEnd": "2025-11-25T18:43:10.000Z" + } + } +} +``` + + + + +## Lenguaje + +* Todo el código está en Java Scrip + +## Estructura del Proyecto + +``` +predict/ +│── controllers/ +│──│── predictControllers.js +│── model/ +│──│── group1-shard1of1.bin +│──│── model.json +│──│── Prediction.js +│── node_modules/ +│── routes/ +│──│── predictRoutes.js +│── services/ +│──│── tfModelService.js +│── dockerfile +│── package-lock.json +│── package.json +│── server_all.js +│── server.js +│── README.md + +``` + + +## Licencia + +Este proyecto está bajo la licencia MIT. From cd8913e4bc3caa26e27992763aae86af3993bd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patricia=20P=C3=A9rez=20Ferre?= Date: Thu, 18 Dec 2025 22:56:15 +0100 Subject: [PATCH 11/13] Enhance README with model and prediction details Update README to include model description and usage. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bba374e..13c0c78d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # PREDICT - +Predict contiene un modelo preentrenado con ```TensorFlow```. Una vez confirma que el modelo está correctamente cargado y que los datos tienen el tamaño correcto (el que debe devolver acquire), se ejecuta obteniendo una predicción del consumo de energía. Este resultado se almacena en ```MongoDB```. ## Repositorios del proyecto ```bash From 6642c14ae7e85dc4d9b70a8ee96bd5203e7a4ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patricia=20P=C3=A9rez=20Ferre?= Date: Thu, 18 Dec 2025 22:57:22 +0100 Subject: [PATCH 12/13] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..c1d05aea --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Orchestrator + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 5699373eab2ecadd555cb00f1dce39beb395b92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patricia=20P=C3=A9rez=20Ferre?= Date: Thu, 18 Dec 2025 22:57:49 +0100 Subject: [PATCH 13/13] Update copyright holder in LICENSE file --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index c1d05aea..5a78a6a5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Orchestrator +Copyright (c) 2025 Predict Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal