Browse Source

Refactoring

pull/5025/head
Thomas Kaul 3 days ago
parent
commit
5240200b18
  1. 40
      apps/api/src/app/endpoints/ai/ai.controller.ts
  2. 2
      apps/api/src/app/endpoints/ai/ai.module.ts
  3. 43
      apps/api/src/app/endpoints/ai/ai.service.ts
  4. 3
      apps/api/src/services/data-provider/data-provider.module.ts
  5. 1
      libs/common/src/lib/config.ts
  6. 6
      package-lock.json

40
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)

2
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

43
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)
});
}

3
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 {}

1
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';

6
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"

Loading…
Cancel
Save