polysignal_hackaton / backend /src /signals /signals.service.js
blackmistcode's picture
Add files using upload-large-folder tool
0dc7194 verified
Raw
History Blame Contribute Delete
2.49 kB
/**
* Logica de negocio del modulo de senales IA.
*
* Responsabilidades:
* - getLatest(marketId) β†’ devuelve la ultima senal persistida de un mercado.
* - generateForMarket(market) β†’ ejecuta el pipeline de IA (aiPipeline.js) y persiste
* el resultado en AISignal. Emite evento 'ai_signal' por Socket.io.
*
* Flujo de generacion:
* 1. aiPipeline.run(market) β†’ obtiene { signal, confidence, summary, keyRisk, newsCount }.
* 2. signalsRepository.create(...) β†’ persiste en SQLite.
* 3. emitAiSignal(...) β†’ notifica a clientes conectados en tiempo real.
*
* Consumido por:
* - scheduler.js cada 5 minutos para los 20 mercados mas activos.
* - signals.controller.js para el endpoint GET /markets/:id/signal.
*/
import { HttpError } from '../utils/apiResponse.js';
import { signalsRepository } from './signals.repository.js';
import { marketsRepository } from '../markets/markets.repository.js';
import * as aiPipeline from './aiPipeline.js';
import { emitAiSignal } from '../socket/broadcaster.js';
import { logger } from '../utils/logger.js';
export const signalsService = {
async getLatest(marketId) {
const market = await marketsRepository.findById(marketId);
if (!market) throw new HttpError(404, 'NOT_FOUND', 'Market not found');
const signal = await signalsRepository.findLatestByMarket(marketId);
if (!signal) throw new HttpError(404, 'NOT_FOUND', 'No signal available for this market yet');
return signal;
},
async getLatestBatch(marketIds) {
if (!marketIds || marketIds.length === 0) return [];
const signals = await signalsRepository.findLatestForMarkets(marketIds);
return signals;
},
async generateForMarket(market) {
// Saltar mercados no analizables (sports, predicciones de palabras, memes).
// Mejor "sin senal" que confianza falsa.
if (market.analyzable === false) {
logger.debug({ marketId: market.id, question: market.question }, 'skipping non-analyzable market');
return null;
}
const result = await aiPipeline.run(market);
const modelVersion = result.modelVersion || 'Unknown';
const saved = await signalsRepository.create({ marketId: market.id, modelVersion, ...result });
emitAiSignal({ marketId: market.id, signal: saved.signal, confidence: saved.confidence, summary: saved.summary, modelVersion: saved.modelVersion });
logger.info({ marketId: market.id, signal: saved.signal }, 'signal generated');
return saved;
},
};