| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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) { |
| |
| |
| 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; |
| }, |
| }; |
|
|