From 5240200b186510e0a1bc489d785fa6448e1ef0af Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 28 Jun 2025 16:46:19 +0200 Subject: [PATCH] Refactoring --- .../api/src/app/endpoints/ai/ai.controller.ts | 40 ----------------- apps/api/src/app/endpoints/ai/ai.module.ts | 2 + apps/api/src/app/endpoints/ai/ai.service.ts | 43 +++++-------------- .../data-provider/data-provider.module.ts | 3 +- libs/common/src/lib/config.ts | 1 - package-lock.json | 6 +-- 6 files changed, 17 insertions(+), 78 deletions(-) diff --git a/apps/api/src/app/endpoints/ai/ai.controller.ts b/apps/api/src/app/endpoints/ai/ai.controller.ts index b654fcf4a..8050c675b 100644 --- a/apps/api/src/app/endpoints/ai/ai.controller.ts +++ b/apps/api/src/app/endpoints/ai/ai.controller.ts @@ -10,14 +10,11 @@ import { Get, Inject, Param, - Post, Query, - Res, UseGuards } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; -import { Response } from 'express'; import { AiService } from './ai.service'; @@ -29,43 +26,6 @@ export class AiController { @Inject(REQUEST) private readonly request: RequestWithUser ) {} - @Post('completion') - @HasPermission(permissions.readAiPrompt) - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async getCompletion( - @Res() response: Response, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string - ) { - const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags - }); - - const result = await this.aiService.getCompletion({ - filters, - mode: 'analysis', - impersonationId: undefined, - languageCode: this.request.user.Settings.settings.language, - userCurrency: this.request.user.Settings.settings.baseCurrency, - userId: this.request.user.id - }); - - response.setHeader('Content-Type', 'text/plain'); - - for await (const chunk of result.textStream) { - response.write(chunk); - } - - response.end(); - } - @Get('prompt/:mode') @HasPermission(permissions.readAiPrompt) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) diff --git a/apps/api/src/app/endpoints/ai/ai.module.ts b/apps/api/src/app/endpoints/ai/ai.module.ts index 42480efd7..8a441fde7 100644 --- a/apps/api/src/app/endpoints/ai/ai.module.ts +++ b/apps/api/src/app/endpoints/ai/ai.module.ts @@ -17,6 +17,7 @@ import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impe import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; @@ -39,6 +40,7 @@ import { AiService } from './ai.service'; OrderModule, PortfolioSnapshotQueueModule, PrismaModule, + PropertyModule, RedisCacheModule, SymbolProfileModule, UserModule diff --git a/apps/api/src/app/endpoints/ai/ai.service.ts b/apps/api/src/app/endpoints/ai/ai.service.ts index 25109eaa0..e56ee062d 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.ts +++ b/apps/api/src/app/endpoints/ai/ai.service.ts @@ -9,7 +9,7 @@ import type { AiPromptMode } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; -import { streamText } from 'ai'; +import { generateText } from 'ai'; @Injectable() export class AiService { @@ -18,45 +18,22 @@ export class AiService { private readonly propertyService: PropertyService ) {} - public async getCompletion({ - filters, - impersonationId, - languageCode, - mode, - userCurrency, - userId - }: { - filters?: Filter[]; - impersonationId: string; - languageCode: string; - mode: AiPromptMode; - userCurrency: string; - userId: string; - }) { - const prompt = await this.getPrompt({ - filters, - impersonationId, - languageCode, - mode, - userCurrency, - userId - }); - - const openRouterApiKey = await this.propertyService.getByKey( + public async generateText({ prompt }: { prompt: string }) { + const openRouterApiKey = (await this.propertyService.getByKey( PROPERTY_API_KEY_OPENROUTER - ); + )) as string; - const openRouterModel = await this.propertyService.getByKey( + const openRouterModel = (await this.propertyService.getByKey( PROPERTY_OPENROUTER_MODEL - ); + )) as string; - const { chat } = createOpenRouter({ - apiKey: openRouterApiKey as string + const openRouterService = createOpenRouter({ + apiKey: openRouterApiKey }); - return streamText({ + return generateText({ prompt, - model: chat(openRouterModel as string) + model: openRouterService.chat(openRouterModel) }); } diff --git a/apps/api/src/services/data-provider/data-provider.module.ts b/apps/api/src/services/data-provider/data-provider.module.ts index 9c5359520..71b54f01e 100644 --- a/apps/api/src/services/data-provider/data-provider.module.ts +++ b/apps/api/src/services/data-provider/data-provider.module.ts @@ -79,6 +79,7 @@ import { DataProviderService } from './data-provider.service'; ] }, YahooFinanceDataEnhancerService - ] + ], + exports: [DataProviderService, ManualService, YahooFinanceService] }) export class DataProviderModule {} diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index df652079d..336235e58 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -113,7 +113,6 @@ export const NUMERICAL_PRECISION_THRESHOLD = 100000; export const PROPERTY_API_KEY_GHOSTFOLIO = 'API_KEY_GHOSTFOLIO'; export const PROPERTY_API_KEY_OPENROUTER = 'API_KEY_OPENROUTER'; - export const PROPERTY_BENCHMARKS = 'BENCHMARKS'; export const PROPERTY_BETTER_UPTIME_MONITOR_ID = 'BETTER_UPTIME_MONITOR_ID'; export const PROPERTY_COUNTRIES_OF_SUBSCRIBERS = 'COUNTRIES_OF_SUBSCRIBERS'; diff --git a/package-lock.json b/package-lock.json index de3205aeb..701bb1686 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36003,9 +36003,9 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.24.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", - "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", "license": "ISC", "peerDependencies": { "zod": "^3.24.1"