96a752ecf7
- Restructured server layer with 5 domains: shared, screener, portfolio, calls, finance - Migrated 58 TypeScript files to domain-driven structure - Updated CLAUDE.md with new architecture documentation - Added .gitignore rules for .md files (except CLAUDE.md) - Removed unused CatalystAnalyst import from app.ts - Fixed lint errors: removed unused imports, fixed regex escape, added console suppressions - Verified no sensitive data in git history - Server code compiles cleanly with TypeScript strict mode
40 lines
1.4 KiB
TypeScript
40 lines
1.4 KiB
TypeScript
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 {
|
|
private readonly catalystAnalyst: CatalystAnalyst;
|
|
|
|
constructor(
|
|
private readonly catalystCache: CatalystCache,
|
|
private readonly llm: LLMAnalyst,
|
|
) {
|
|
// Create a fresh instance for per-ticker story fetching (not cached)
|
|
this.catalystAnalyst = new CatalystAnalyst();
|
|
}
|
|
|
|
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 tickers = (req.body as { tickers: string[] }).tickers.map((t) => t.toUpperCase());
|
|
|
|
const stories = await this.catalystAnalyst.fetchStoriesForTickers(tickers);
|
|
if (!stories.length) return reply.code(200).send({ analysis: null, reason: 'no_stories' });
|
|
|
|
const { tickerFrequency } = CatalystAnalyst.rankTickers(stories);
|
|
const analysis = await this.llm.analyze(stories, tickers, tickerFrequency);
|
|
return { analysis };
|
|
}
|
|
}
|