Browse Source

Feature/support filters in AI prompt API (#4431)

* Support filters in AI prompt API

* Update changelog
pull/4452/head^2
csehatt741 2 days ago
committed by GitHub
parent
commit
efc0b1bf5a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 27
      apps/api/src/app/endpoints/ai/ai.controller.ts
  3. 2
      apps/api/src/app/endpoints/ai/ai.module.ts
  4. 4
      apps/api/src/app/endpoints/ai/ai.service.ts
  5. 5
      apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts
  6. 14
      apps/client/src/app/services/data.service.ts

4
CHANGELOG.md

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- Added support for filtering in the _Copy AI prompt to clipboard_ actions on the analysis page (experimental)
### Changed
- Improved the symbol validation in the _Yahoo Finance_ service (get asset profiles)

27
apps/api/src/app/endpoints/ai/ai.controller.ts

@ -1,5 +1,6 @@
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { ApiService } from '@ghostfolio/api/services/api/api.service';
import {
DEFAULT_CURRENCY,
DEFAULT_LANGUAGE_CODE
@ -8,7 +9,14 @@ import { AiPromptResponse } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import type { AiPromptMode, RequestWithUser } from '@ghostfolio/common/types';
import { Controller, Get, Inject, Param, UseGuards } from '@nestjs/common';
import {
Controller,
Get,
Inject,
Param,
Query,
UseGuards
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
@ -18,6 +26,7 @@ import { AiService } from './ai.service';
export class AiController {
public constructor(
private readonly aiService: AiService,
private readonly apiService: ApiService,
@Inject(REQUEST) private readonly request: RequestWithUser
) {}
@ -25,9 +34,23 @@ export class AiController {
@HasPermission(permissions.readAiPrompt)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getPrompt(
@Param('mode') mode: AiPromptMode
@Param('mode') mode: AiPromptMode,
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string
): Promise<AiPromptResponse> {
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags
});
const prompt = await this.aiService.getPrompt({
filters,
mode,
impersonationId: undefined,
languageCode:

2
apps/api/src/app/endpoints/ai/ai.module.ts

@ -7,6 +7,7 @@ import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.servic
import { RulesService } from '@ghostfolio/api/app/portfolio/rules.service';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
@ -25,6 +26,7 @@ import { AiService } from './ai.service';
@Module({
controllers: [AiController],
imports: [
ApiModule,
ConfigurationModule,
DataProviderModule,
ExchangeRateDataModule,

4
apps/api/src/app/endpoints/ai/ai.service.ts

@ -1,4 +1,5 @@
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { Filter } from '@ghostfolio/common/interfaces';
import type { AiPromptMode } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
@ -8,12 +9,14 @@ export class AiService {
public constructor(private readonly portfolioService: PortfolioService) {}
public async getPrompt({
filters,
impersonationId,
languageCode,
mode,
userCurrency,
userId
}: {
filters?: Filter[];
impersonationId: string;
languageCode: string;
mode: AiPromptMode;
@ -21,6 +24,7 @@ export class AiService {
userId: string;
}) {
const { holdings } = await this.portfolioService.getDetails({
filters,
impersonationId,
userId
});

5
apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts

@ -161,7 +161,10 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
}
this.dataService
.fetchPrompt(mode)
.fetchPrompt({
mode,
filters: this.userService.getFilters()
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ prompt }) => {
this.clipboard.copy(prompt);

14
apps/client/src/app/services/data.service.ts

@ -653,8 +653,18 @@ export class DataService {
return this.http.get<PortfolioReportResponse>('/api/v1/portfolio/report');
}
public fetchPrompt(mode: AiPromptMode) {
return this.http.get<AiPromptResponse>(`/api/v1/ai/prompt/${mode}`);
public fetchPrompt({
filters,
mode
}: {
filters?: Filter[];
mode: AiPromptMode;
}) {
const params = this.buildFiltersAsQueryParams({ filters });
return this.http.get<AiPromptResponse>(`/api/v1/ai/prompt/${mode}`, {
params
});
}
public fetchPublicPortfolio(aAccessId: string) {

Loading…
Cancel
Save