diff --git a/apps/api/src/app/endpoints/ai/ai.service.ts b/apps/api/src/app/endpoints/ai/ai.service.ts index 4cc4fde65..cedc1ea3f 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.ts +++ b/apps/api/src/app/endpoints/ai/ai.service.ts @@ -10,7 +10,17 @@ import type { AiPromptMode } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; import { generateText } from 'ai'; -import type { ColumnDescriptor } from 'tablemark'; +import tablemark, { ColumnDescriptor } from 'tablemark'; + +// Column name constants for holdings table +const HOLDINGS_TABLE_COLUMNS = { + CURRENCY: 'Currency', + NAME: 'Name', + SYMBOL: 'Symbol', + ASSET_CLASS: 'Asset Class', + ALLOCATION_PERCENTAGE: 'Allocation in Percentage', + ASSET_SUB_CLASS: 'Asset Sub Class' +} as const; @Injectable() export class AiService { @@ -60,12 +70,12 @@ export class AiService { }); const holdingsTableColumns: ColumnDescriptor[] = [ - { name: 'Name' }, - { name: 'Symbol' }, - { name: 'Currency' }, - { name: 'Asset Class' }, - { name: 'Asset Sub Class' }, - { align: 'right', name: 'Allocation in Percentage' } + { name: HOLDINGS_TABLE_COLUMNS.CURRENCY }, + { name: HOLDINGS_TABLE_COLUMNS.NAME }, + { name: HOLDINGS_TABLE_COLUMNS.SYMBOL }, + { name: HOLDINGS_TABLE_COLUMNS.ASSET_CLASS }, + { align: 'right', name: HOLDINGS_TABLE_COLUMNS.ALLOCATION_PERCENTAGE }, + { name: HOLDINGS_TABLE_COLUMNS.ASSET_SUB_CLASS } ]; const holdingsTableRows = Object.values(holdings) @@ -82,23 +92,16 @@ export class AiService { symbol }) => { return { - Name: name, - Symbol: symbol, - Currency: currency, - 'Asset Class': assetClass ?? '', - 'Asset Sub Class': assetSubClass ?? '', - 'Allocation in Percentage': `${(allocationInPercentage * 100).toFixed(3)}%` + [HOLDINGS_TABLE_COLUMNS.CURRENCY]: currency, + [HOLDINGS_TABLE_COLUMNS.NAME]: name, + [HOLDINGS_TABLE_COLUMNS.SYMBOL]: symbol, + [HOLDINGS_TABLE_COLUMNS.ASSET_CLASS]: assetClass ?? '', + [HOLDINGS_TABLE_COLUMNS.ALLOCATION_PERCENTAGE]: `${(allocationInPercentage * 100).toFixed(3)}%`, + [HOLDINGS_TABLE_COLUMNS.ASSET_SUB_CLASS]: assetSubClass ?? '' }; } ); - // Dynamic import to load ESM module from CommonJS context - // eslint-disable-next-line @typescript-eslint/no-implied-eval - const dynamicImport = new Function('s', 'return import(s)') as ( - s: string - ) => Promise; - const { tablemark } = await dynamicImport('tablemark'); - const holdingsTableString = tablemark(holdingsTableRows, { columns: holdingsTableColumns });