import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; import type { LLMAnalyst } from '../../domains/shared'; import { CatalystCache, CatalystAnalyst } from '../../domains/shared'; import { analyzeSchema } from '../../domains/shared/types/schemas'; export class AnalyzeController { constructor( private readonly catalystCache: CatalystCache, private readonly llm: LLMAnalyst, ) {} register(app: FastifyInstance): void { app.post( '/api/analyze', { schema: analyzeSchema, config: { rateLimit: { max: 10, timeWindow: '1 minute' } } }, this.analyze.bind(this), ); } private async analyze(req: FastifyRequest, reply: FastifyReply) { if (!this.llm.isAvailable) { return reply.code(400).send({ error: 'ANTHROPIC_API_KEY is not set in .env' }); } const requestedTickers = (req.body as { tickers: string[] }).tickers.map((t) => t.toUpperCase(), ); const { stories: allStories } = await this.catalystCache.get(); const stories = allStories.filter((story) => story.tickers.some((t) => requestedTickers.includes(t)), ); if (!stories.length) return reply.code(200).send({ analysis: null, reason: 'no_stories' }); const { tickerFrequency } = CatalystAnalyst.rankTickers(stories); let analysis = null; try { analysis = await this.llm.analyze(stories, requestedTickers, tickerFrequency); } catch (err) { req.log.error({ err }, 'LLM analysis failed'); } return { analysis }; } }