@ -1,5 +1,6 @@
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service' ;
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service' ;
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service' ;
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service' ;
import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service' ;
import { PropertyService } from '@ghostfolio/api/services/property/property.service' ;
import { PropertyService } from '@ghostfolio/api/services/property/property.service' ;
import {
import {
PROPERTY_API_KEY_OPENROUTER ,
PROPERTY_API_KEY_OPENROUTER ,
@ -11,6 +12,7 @@ import type { AiPromptMode } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common' ;
import { Injectable } from '@nestjs/common' ;
import { createOpenRouter } from '@openrouter/ai-sdk-provider' ;
import { createOpenRouter } from '@openrouter/ai-sdk-provider' ;
import { AssetClass , AssetSubClass } from '@prisma/client' ;
import { generateText } from 'ai' ;
import { generateText } from 'ai' ;
import { format } from 'date-fns' ;
import { format } from 'date-fns' ;
import type { ColumnDescriptor } from 'tablemark' ;
import type { ColumnDescriptor } from 'tablemark' ;
@ -44,6 +46,7 @@ export class AiService {
public constructor (
public constructor (
private readonly configurationService : ConfigurationService ,
private readonly configurationService : ConfigurationService ,
private readonly i18nService : I18nService ,
private readonly portfolioService : PortfolioService ,
private readonly portfolioService : PortfolioService ,
private readonly propertyService : PropertyService
private readonly propertyService : PropertyService
) { }
) { }
@ -103,6 +106,18 @@ export class AiService {
return { name , align : align ? ? 'left' } ;
return { name , align : align ? ? 'left' } ;
} ) ;
} ) ;
const assetClassTranslations = this . getEnumTranslations ( {
languageCode ,
id : 'assetClass' ,
values : Object.values ( AssetClass )
} ) ;
const assetSubClassTranslations = this . getEnumTranslations ( {
languageCode ,
id : 'assetSubClass' ,
values : Object.values ( AssetSubClass )
} ) ;
const holdingsTableRows = Object . values ( holdings )
const holdingsTableRows = Object . values ( holdings )
. sort ( ( a , b ) = > {
. sort ( ( a , b ) = > {
return b . allocationInPercentage - a . allocationInPercentage ;
return b . allocationInPercentage - a . allocationInPercentage ;
@ -132,11 +147,11 @@ export class AiService {
break ;
break ;
case 'ASSET_CLASS' :
case 'ASSET_CLASS' :
row [ name ] = assetClass ? ? '' ;
row [ name ] = assetClassTranslations [ assetClass ] ? ? '' ;
break ;
break ;
case 'ASSET_SUB_CLASS' :
case 'ASSET_SUB_CLASS' :
row [ name ] = assetSubClass ? ? '' ;
row [ name ] = assetSubClassTranslations [ assetSubClass ] ? ? '' ;
break ;
break ;
case 'CURRENCY' :
case 'CURRENCY' :
@ -202,4 +217,27 @@ export class AiService {
` Provide your answer in the following language: ${ languageCode } . `
` Provide your answer in the following language: ${ languageCode } . `
] . join ( '\n' ) ;
] . join ( '\n' ) ;
}
}
private getEnumTranslations < T extends string > ( {
id ,
languageCode ,
values
} : {
id : string ;
languageCode : string ;
values : T [ ] ;
} ) {
return values . reduce (
( translations , value ) = > {
translations [ value ] =
this . i18nService . getTranslation ( {
languageCode ,
id : ` ${ id } . ${ value } `
} ) || value ;
return translations ;
} ,
{ } as Record < T , string >
) ;
}
}
}