From a21dc4d6a0273bd6cb775a8a17d32d1a9f423764 Mon Sep 17 00:00:00 2001 From: jacekpluta <73617938+jacekpluta@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:29:32 +0200 Subject: [PATCH] [ACS-8399] Integrate all changes with backend (#10163) --- .../services/agent.service.md | 3 +- .../services/search-ai.service.md | 4 +- .../lib/agent/services/agent.service.spec.ts | 3 +- .../src/lib/agent/services/agent.service.ts | 58 ++----------------- .../services/search-ai.service.spec.ts | 8 +-- .../search-ai/services/search-ai.service.ts | 53 ++--------------- .../api/content-rest-api/api/search-ai.api.ts | 18 +++--- .../api/content-rest-api/docs/SearchAiApi.md | 22 +++++-- .../content-rest-api/model/questionModel.ts | 6 +- .../content-rest-api/model/questionRequest.ts | 1 + .../model/restrictionQuery.ts | 20 +++++++ 11 files changed, 66 insertions(+), 130 deletions(-) create mode 100644 lib/js-api/src/api/content-rest-api/model/restrictionQuery.ts diff --git a/docs/content-services/services/agent.service.md b/docs/content-services/services/agent.service.md index c92ddf9cca..5a7afa0e06 100644 --- a/docs/content-services/services/agent.service.md +++ b/docs/content-services/services/agent.service.md @@ -13,9 +13,8 @@ Manages agents in Content Services. ### Methods -- **getAgents**(mocked?: `boolean`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AgentPaging`](../../../lib/js-api/src/api/content-rest-api/docs/AgentsApi.md#agentpaging)`>`
+- **getAgents**(): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AgentPaging`](../../../lib/js-api/src/api/content-rest-api/docs/AgentsApi.md#agentpaging)`>`
Gets all agents. - - _mocked:_ `boolean` - (Optional) Temporary parameter to mock agents. Should be removed when backend implemented. True by default. - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AgentPaging`](../../../lib/js-api/src/api/content-rest-api/docs/AgentsApi.md#agentpaging)`>` - AgentPaging object containing the agents. ## Details diff --git a/docs/content-services/services/search-ai.service.md b/docs/content-services/services/search-ai.service.md index e1be562d0f..524d6235e0 100644 --- a/docs/content-services/services/search-ai.service.md +++ b/docs/content-services/services/search-ai.service.md @@ -19,12 +19,10 @@ Manages search AI in Content Services. - **ask**(question: [`QuestionRequest`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionrequest)): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`QuestionModel`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionmodel)`>`
Ask a question to the AI. - _question:_ [`QuestionRequest`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionrequest) - The question to ask. - - _mocked:_ `boolean` - (Optional) temporary parameter to mock returned information about question. Should be removed when backend implemented. True by default. - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`QuestionModel`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionmodel)`>` - QuestionModel object containing information about questions. -- **getAnswer**(questionId: `string`, mocked?: `boolean`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AiAnswerPaging`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#aianswerpaging)`>`
+- **getAnswer**(questionId: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AiAnswerPaging`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#aianswerpaging)`>`
Get an answer to specific question. - _questionId:_ `string` - The ID of the question to get an answer for. - - _mocked:_ `boolean` - (Optional) temporary parameter to mock answer on question. Should be removed when backend implemented. True by default. - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AiAnswerPaging`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#aianswerpaging)`>` - AiAnswerPaging object containing the answer. - **checkSearchAvailability**(selectedNodesState: `SelectionState`, maxSelectedNodes: `number`): `string`
Check if using of search is possible (if all conditions are met). diff --git a/lib/content-services/src/lib/agent/services/agent.service.spec.ts b/lib/content-services/src/lib/agent/services/agent.service.spec.ts index 69cea0dae0..78e9361e8e 100644 --- a/lib/content-services/src/lib/agent/services/agent.service.spec.ts +++ b/lib/content-services/src/lib/agent/services/agent.service.spec.ts @@ -45,7 +45,7 @@ const agentPagingObjectMock: AgentPaging = { } }; -const avatarAgentMock = 'https://res.cloudinary.com/hyld/image/upload/f_auto,c_fill,g_auto,w_1400,h_730/v1/h2/hero/blue-shirt-woman'; +const avatarAgentMock = ''; const agentWithAvatarListMock: AgentWithAvatar[] = [ { @@ -71,7 +71,6 @@ describe('AgentService', () => { agentService = TestBed.inject(AgentService); apiService = TestBed.inject(AlfrescoApiService); agentsApi = new AgentsApi(apiService.getInstance()); - agentService.mocked = false; spyOn(agentsApi, 'getAgentAvatar').and.returnValue(Promise.resolve(avatarAgentMock)); spyOn(agentService.agentsApi, 'getAgentAvatar').and.returnValue(Promise.resolve(avatarAgentMock)); diff --git a/lib/content-services/src/lib/agent/services/agent.service.ts b/lib/content-services/src/lib/agent/services/agent.service.ts index 887420a23e..a0de4f6f6b 100644 --- a/lib/content-services/src/lib/agent/services/agent.service.ts +++ b/lib/content-services/src/lib/agent/services/agent.service.ts @@ -16,7 +16,7 @@ */ import { Injectable } from '@angular/core'; -import { AgentPaging, AgentsApi, AgentWithAvatar } from '@alfresco/js-api'; +import { AgentsApi, AgentWithAvatar } from '@alfresco/js-api'; import { AlfrescoApiService } from '@alfresco/adf-core'; import { BehaviorSubject, forkJoin, from, Observable, of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; @@ -26,7 +26,6 @@ import { switchMap } from 'rxjs/operators'; }) export class AgentService { private _agentsApi: AgentsApi; - private _mocked = true; private agents = new BehaviorSubject([]); get agentsApi(): AgentsApi { @@ -34,10 +33,6 @@ export class AgentService { return this._agentsApi; } - set mocked(mocked: boolean) { - this._mocked = mocked; - } - agents$ = this.agents.asObservable(); constructor(private apiService: AlfrescoApiService) {} @@ -53,12 +48,13 @@ export class AgentService { if (agentsList.length) { return of(agentsList); } - return this.getMockedAgents().pipe( + return from(this.agentsApi.getAgents()).pipe( switchMap((paging) => { const agents = paging.list.entries.map((agentEntry) => agentEntry.entry); - return forkJoin([of(agents), ...agents.map((agent) => this.getAgentAvatar(agent.id))]); + // TODO: fetch avatars https://hyland.atlassian.net/browse/ACS-8695 + return forkJoin({ agents: of(agents), avatars: forkJoin(agents.map(() => of(``))) }); }), - switchMap(([agents, ...avatars]: [AgentWithAvatar[], string]) => { + switchMap(({ agents, avatars }) => { const agentsWithAvatar = agents.map((agent, index) => ({ ...agent, avatar: avatars[index] })); this.agents.next(agentsWithAvatar); return of(agentsWithAvatar); @@ -68,46 +64,6 @@ export class AgentService { ); } - /** - * Gets all agents. - * - * @returns AgentPaging object containing the agents. - */ - private getMockedAgents(): Observable { - return this._mocked - ? of({ - list: { - entries: [ - { - entry: { - id: '1', - name: 'HR Agent', - description: - 'Your Claims Doc Agent streamlines the extraction, analysis, and management of data from insurance claims documents.' - } - }, - { - entry: { - id: '2', - name: 'Policy Agent', - description: - 'Your Claims Doc Agent streamlines the extraction, analysis, and management of data from insurance claims documents.' - } - }, - { - entry: { - id: '3', - name: 'Rules & Rates Agent', - description: - 'Your Claims Doc Agent streamlines the extraction, analysis, and management of data from insurance claims documents.' - } - } - ] - } - }) - : from(this.agentsApi.getAgents()); - } - /** * Gets agent avatar by agent id. * @@ -115,8 +71,6 @@ export class AgentService { * @returns string with an image. */ getAgentAvatar(agentId: string): Observable { - return this._mocked - ? of('https://res.cloudinary.com/hyld/image/upload/f_auto,c_fill,g_auto,w_1400,h_730/v1/h2/hero/blue-shirt-woman') - : from(this._agentsApi.getAgentAvatar(agentId)); + return from(this._agentsApi.getAgentAvatar(agentId)); } } diff --git a/lib/content-services/src/lib/search-ai/services/search-ai.service.spec.ts b/lib/content-services/src/lib/search-ai/services/search-ai.service.spec.ts index 61258c8d03..a45dddab53 100644 --- a/lib/content-services/src/lib/search-ai/services/search-ai.service.spec.ts +++ b/lib/content-services/src/lib/search-ai/services/search-ai.service.spec.ts @@ -30,7 +30,6 @@ describe('SearchAiService', () => { imports: [ContentTestingModule] }); service = TestBed.inject(SearchAiService); - service.mocked = false; }); describe('ask', () => { @@ -38,12 +37,13 @@ describe('SearchAiService', () => { const question: QuestionModel = { question: 'some question', questionId: 'some id', - restrictionQuery: 'node id1,node id 2' + restrictionQuery: { nodesIds: ['nodeId1', 'nodeId2'] } }; - spyOn(service.searchAiApi, 'ask').and.returnValue(Promise.resolve([question])); + spyOn(service.searchAiApi, 'ask').and.returnValue(Promise.resolve(question)); const questionRequest: QuestionRequest = { question: 'some question', - nodeIds: ['node id1', 'node id 2'] + nodeIds: ['nodeId1', 'nodeId2'], + agentId: 'some id' }; service.ask(questionRequest).subscribe((questionResponse) => { diff --git a/lib/content-services/src/lib/search-ai/services/search-ai.service.ts b/lib/content-services/src/lib/search-ai/services/search-ai.service.ts index bb750d2f58..e98878c1f0 100644 --- a/lib/content-services/src/lib/search-ai/services/search-ai.service.ts +++ b/lib/content-services/src/lib/search-ai/services/search-ai.service.ts @@ -18,8 +18,7 @@ import { Injectable } from '@angular/core'; import { AiAnswerPaging, QuestionModel, QuestionRequest, SearchAiApi } from '@alfresco/js-api'; import { AlfrescoApiService } from '@alfresco/adf-core'; -import { BehaviorSubject, from, Observable, of } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { BehaviorSubject, from, Observable } from 'rxjs'; import { SelectionState } from '@alfresco/adf-extensions'; import { TranslateService } from '@ngx-translate/core'; import { SearchAiInputState } from '../models/search-ai-input-state'; @@ -32,23 +31,15 @@ export class SearchAiService { active: false }); private _searchAiApi: SearchAiApi; - private _mocked = true; get searchAiApi(): SearchAiApi { this._searchAiApi = this._searchAiApi ?? new SearchAiApi(this.apiService.getInstance()); return this._searchAiApi; } - set mocked(mocked: boolean) { - this._mocked = mocked; - } - toggleSearchAiInput$ = this.toggleSearchAiInput.asObservable(); - constructor( - private apiService: AlfrescoApiService, - private translateService: TranslateService - ) {} + constructor(private apiService: AlfrescoApiService, private translateService: TranslateService) {} /** * Update the state of the search AI input. @@ -66,13 +57,7 @@ export class SearchAiService { * @returns QuestionModel object containing information about questions. */ ask(question: QuestionRequest): Observable { - return this._mocked - ? of({ - question: 'Some question', - questionId: 'some id', - restrictionQuery: 'Some restriction query' - }) - : from(this.searchAiApi.ask([question])).pipe(map((questions) => questions[0])); + return from(this.searchAiApi.ask([question])); } /** @@ -82,37 +67,7 @@ export class SearchAiService { * @returns AiAnswerPaging object containing the answer. */ getAnswer(questionId: string): Observable { - return this._mocked - ? of({ - list: { - pagination: { - count: 1, - hasMoreItems: false, - totalItems: 1, - skipCount: 0, - maxItems: 100 - }, - entries: [ - { - entry: { - answer: 'Some answer', - questionId: 'some id', - references: [ - { - referenceId: '45a84919-d654-4669-a849-19d6548669e9', - referenceText: 'some type' - }, - { - referenceId: '45a84919-d654-4669-a849-19d6548669e9', - referenceText: 'some type' - } - ] - } - } - ] - } - }) - : from(this.searchAiApi.getAnswer(questionId)); + return from(this.searchAiApi.getAnswer(questionId)); } /** diff --git a/lib/js-api/src/api/content-rest-api/api/search-ai.api.ts b/lib/js-api/src/api/content-rest-api/api/search-ai.api.ts index 745b8b6490..3a0d2529ae 100644 --- a/lib/js-api/src/api/content-rest-api/api/search-ai.api.ts +++ b/lib/js-api/src/api/content-rest-api/api/search-ai.api.ts @@ -27,17 +27,18 @@ export class SearchAiApi extends BaseApi { /** * Ask a question to the AI. * - * @param questions The questions to ask. + * @param questions QuestionRequest array containing questions to ask. * @returns QuestionModel object containing information about questions. */ - ask(questions: QuestionRequest[]): Promise { - return this.get({ - path: 'questions', + ask(questions: QuestionRequest[]): Promise { + const agentId = questions[0].agentId; + return this.post({ + path: `agents/${agentId}/questions`, bodyParam: questions.map((questionRequest) => ({ question: questionRequest.question, - restrictionQuery: questionRequest.nodeIds.join(',') + restrictionQuery: { nodesIds: questionRequest.nodeIds } })) - }); + }).then((response) => response.entry); } /** @@ -48,10 +49,7 @@ export class SearchAiApi extends BaseApi { */ getAnswer(questionId: string): Promise { return this.get({ - path: 'answers', - queryParams: { - questionId - } + path: `questions/${questionId}/answers` }); } } diff --git a/lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md b/lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md index fd1d7801f3..96e49ef423 100644 --- a/lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md +++ b/lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md @@ -30,7 +30,8 @@ const searchAiApi = new SearchAiApi(alfrescoApi); searchAiApi.ask([{ question: 'Some question', - restrictionQuery: 'Some restriction query' + restrictionQuery: 'Some restriction query', + agentId: 'Some agent id' }]).then((questionInformation) => { console.log('API called successfully. Returned data: ' + questionInformation); }); @@ -146,11 +147,19 @@ searchAiApi.getAnswer('some question id').then((answer) => { **Properties** -| Name | Type | -|----------------------|--------| -| **question** | string | -| **questionId** | string | -| **restrictionQuery** | string | +| Name | Type | +|----------------------|------------------| +| **question** | string | +| **questionId** | string | +| **restrictionQuery** | RestrictionQuery | + +## RestrictionQuery + +**Properties** + +| Name | Type | +|--------------|----------| +| **nodesIds** | string[] | ## QuestionRequest @@ -160,3 +169,4 @@ searchAiApi.getAnswer('some question id').then((answer) => { |--------------|----------| | **question** | string | | **nodeIds** | string[] | +| **agentId** | string | diff --git a/lib/js-api/src/api/content-rest-api/model/questionModel.ts b/lib/js-api/src/api/content-rest-api/model/questionModel.ts index 4e88c36c7c..17b994ef44 100644 --- a/lib/js-api/src/api/content-rest-api/model/questionModel.ts +++ b/lib/js-api/src/api/content-rest-api/model/questionModel.ts @@ -15,8 +15,10 @@ * limitations under the License. */ +import { RestrictionQuery } from './restrictionQuery'; + export interface QuestionModel { - question: string; questionId: string; - restrictionQuery: string; + question: string; + restrictionQuery: RestrictionQuery; } diff --git a/lib/js-api/src/api/content-rest-api/model/questionRequest.ts b/lib/js-api/src/api/content-rest-api/model/questionRequest.ts index d2bd6332bd..2eaabfac7a 100644 --- a/lib/js-api/src/api/content-rest-api/model/questionRequest.ts +++ b/lib/js-api/src/api/content-rest-api/model/questionRequest.ts @@ -18,4 +18,5 @@ export interface QuestionRequest { question: string; nodeIds: string[]; + agentId: string; } diff --git a/lib/js-api/src/api/content-rest-api/model/restrictionQuery.ts b/lib/js-api/src/api/content-rest-api/model/restrictionQuery.ts new file mode 100644 index 0000000000..05d5186bcc --- /dev/null +++ b/lib/js-api/src/api/content-rest-api/model/restrictionQuery.ts @@ -0,0 +1,20 @@ +/*! + * @license + * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface RestrictionQuery { + nodesIds: string[]; +}