diff --git a/apps/cloud/src/app/@core/services/copilot-usage.service.ts b/apps/cloud/src/app/@core/services/copilot-usage.service.ts index 17d471fef..74903843c 100644 --- a/apps/cloud/src/app/@core/services/copilot-usage.service.ts +++ b/apps/cloud/src/app/@core/services/copilot-usage.service.ts @@ -14,7 +14,7 @@ export class CopilotUsageService { return this.httpClient .get<{ items: ICopilotOrganization[] }>(API_COPILOT_ORGANIZATION, { params: { - $relations: JSON.stringify(['org']) + $relations: JSON.stringify(['organization']) } }) .pipe(map(({ items }) => items)) diff --git a/apps/cloud/src/app/features/chatbi/answer/answer.component.html b/apps/cloud/src/app/features/chatbi/answer/answer.component.html index ea74e06cb..dbca555c0 100644 --- a/apps/cloud/src/app/features/chatbi/answer/answer.component.html +++ b/apps/cloud/src/app/features/chatbi/answer/answer.component.html @@ -68,9 +68,9 @@ } @case ('chart') { -
-
-
-
-
-
- -
+
+
+
+
+
+
+
-
-
-
- {{'PAC.KEY_WORDS.Copilot' | translate: {Default: 'Copilot'} }}ChatBI -
-
-

{{'PAC.ChatBI.SystemMessage_1' | translate: {value: entityType()?.caption || cube() || '', Default: 'Hello, I am the BI copilot of Metad Analytics Cloud. The current dataset is "'+(entityType()?.caption || cube() || 'Empty')+'". You can click the top to switch.'} }}

-

{{'PAC.ChatBI.SystemMessage_2' | translate: {Default: 'You can also try clicking on the samples'} }}:

-
    - @for (example of examples(); track example) { -
  • - {{example}} -
  • - } -
-
-

{{'PAC.ChatBI.SystemMessage_3' | translate: {Default: 'I can accurately identify problems involving time, conditions, dimensions, and indicators.'} }}

-

{{'PAC.ChatBI.SystemMessage_eg' | translate: {Default: 'e.g.'} }} {{'PAC.ChatBI.SystemMessage_Year' | translate: {Default: '2023 year'} }} {{'PAC.ChatBI.SystemMessage_Cloud' | translate: {Default: 'metad analytics cloud BI'} }} {{'PAC.ChatBI.SystemMessage_Month' | translate: {Default: 'every month'} }} {{'PAC.ChatBI.SystemMessage_Revenue' | translate: {Default: 'revenue'} }} {{'PAC.ChatBI.SystemMessage_HowMuch' | translate: {Default: 'how much'} }}?

-
+
+
+
+
+ {{'PAC.KEY_WORDS.Copilot' | translate: {Default: 'Copilot'} }}ChatBI +
+
+

{{'PAC.ChatBI.SystemMessage_1' | translate: {value: entityType()?.caption || cube() || '', Default: 'Hello, I am the BI copilot of Metad Analytics Cloud. The current dataset is "'+(entityType()?.caption || cube() || 'Empty')+'". You can click the top to switch.'} }}

+

{{'PAC.ChatBI.SystemMessage_2' | translate: {Default: 'You can also try clicking on the samples'} }}:

+
    + @for (example of examples(); track example) { +
  • + {{example}} +
  • + } +
+
+

{{'PAC.ChatBI.SystemMessage_3' | translate: {Default: 'I can accurately identify problems involving time, conditions, dimensions, and indicators.'} }}

+

{{'PAC.ChatBI.SystemMessage_eg' | translate: {Default: 'e.g.'} }} {{'PAC.ChatBI.SystemMessage_Year' | translate: {Default: '2023 year'} }} {{'PAC.ChatBI.SystemMessage_Cloud' | translate: {Default: 'metad analytics cloud BI'} }} {{'PAC.ChatBI.SystemMessage_Month' | translate: {Default: 'every month'} }} {{'PAC.ChatBI.SystemMessage_Revenue' | translate: {Default: 'revenue'} }} {{'PAC.ChatBI.SystemMessage_HowMuch' | translate: {Default: 'how much'} }}?

+
- @for (message of conversation()?.messages; track $index) { - @switch (message.role) { - @case ('assistant') { -
-
-
-
- -
+ @for (message of conversation()?.messages; track $index) { + @switch (message.role) { + @case ('assistant') { +
+
+
+
+
-
-
-
- {{'PAC.KEY_WORDS.Copilot' | translate: {Default: 'Copilot'} }}ChatBI -
- -
-
- {{ message.createdAt | date: 'short' }} +
+
+
+
+ {{'PAC.KEY_WORDS.Copilot' | translate: {Default: 'Copilot'} }}ChatBI
+ +
+
+ {{ message.createdAt | date: 'short' }}
- } - @case ('user') { -
-
-
- - - +
+ } + @case ('user') { +
+
+
+ + + +
+
+
+
{{'PAC.KEY_WORDS.You' | translate: {Default: 'You'} }}
+
+

{{ message.content }}

-
-
-
{{'PAC.KEY_WORDS.You' | translate: {Default: 'You'} }}
-
-

{{ message.content }}

-
-
- {{ message.createdAt | date: 'short' }} - -
+
+ {{ message.createdAt | date: 'short' }} +
- } +
} } -
+ }
+
- +
diff --git a/apps/cloud/src/app/features/chatbi/home.component.html b/apps/cloud/src/app/features/chatbi/home.component.html index bbec4abbf..22b946f64 100644 --- a/apps/cloud/src/app/features/chatbi/home.component.html +++ b/apps/cloud/src/app/features/chatbi/home.component.html @@ -1,17 +1,28 @@ -
-
+

{{ 'PAC.ChatBI.Title' | translate: {Default: 'ChatBI-Data Analysis & Insights with' } }} - + + @if (isMobile()) { + + {{cube() ? cube().caption || cube().name : ('PAC.ChatBI.SelectCube' | translate: {Default: 'Select Cube' })}} + }

{{ 'PAC.ChatBI.TransformData' | translate: {Default: 'Transform data into insights with AI.' } }} @@ -19,13 +30,15 @@

- - + +
-
@if (showExplorer()) { (null) + readonly modelTooltip = viewChild('mTooltip', { read: MatTooltip }) + get modelId() { return this.chatbiService.modelId() } @@ -61,6 +66,8 @@ export class ChatbiHomeComponent { this.chatbiService.setModelId(value) } + readonly isMobile = this.appService.isMobile + readonly openCubes = signal(false) readonly models = toSignal( this.chatbiService.models$.pipe( map((models) => @@ -74,6 +81,9 @@ export class ChatbiHomeComponent { ) readonly hasModel = computed(() => this.models()?.length > 0) readonly _conversationId = computed(() => this.chatbiService.conversation()?.id) + readonly cubeName = this.chatbiService.entity + readonly cubes = this.chatbiService.cubes + readonly cube = computed(() => this.cubes()?.find((item) => item.name === this.cubeName())) // Story explorer readonly showExplorer = signal(false) @@ -116,6 +126,12 @@ export class ChatbiHomeComponent { }, { allowSignalWrites: true } ) + + effect(() => { + if (!this.chatbiService.modelId() && this.models()?.length) { + this.modelTooltip().show() + } + }) } async openExplore(message: CopilotChatMessage, answer: QuestionAnswer) { @@ -131,4 +147,8 @@ export class ChatbiHomeComponent { this.chatbiService.updateQuestionAnswer(this.explore().key, event) } } + + openSelectCube() { + this.openCubes.set(true) + } } diff --git a/apps/cloud/src/app/features/chatbi/input/input.component.html b/apps/cloud/src/app/features/chatbi/input/input.component.html index 6584a864a..7d9f8d612 100644 --- a/apps/cloud/src/app/features/chatbi/input/input.component.html +++ b/apps/cloud/src/app/features/chatbi/input/input.component.html @@ -1,74 +1,77 @@
-
-
- -
+
+
+ +
- + [matAutocomplete]="autoPrompts" + matAutocompletePosition="above" + > - - @for (command of prompts(); track command.prompt) { - - /{{command.name}} - @if (command.alias) { - /{{command.alias}} - } - {{command.description}} - + + @for (command of prompts(); track command.prompt) { + + /{{command.name}} + @if (command.alias) { + /{{command.alias}} } - - -
- @if (answering()) { - - } @else { - - } -
+ {{command.description}} + + } +
+ +
+ @if (answering()) { + + } @else { + + }
-
+
+
@if (!copilotEnabled()) {
+ @if (isMobile()) { + + }

{{ 'PAC.ChatBI.Cubes' | translate: {Default: 'Cubes'} }}

+ +
-
+
diff --git a/apps/cloud/src/app/features/chatbi/models/models.component.ts b/apps/cloud/src/app/features/chatbi/models/models.component.ts index a6132abfc..109fb7940 100644 --- a/apps/cloud/src/app/features/chatbi/models/models.component.ts +++ b/apps/cloud/src/app/features/chatbi/models/models.component.ts @@ -11,6 +11,9 @@ import { ChatbiService } from '../chatbi.service' import { ScrollingModule } from '@angular/cdk/scrolling' import { MatProgressSpinnerModule } from '@angular/material/progress-spinner' import { NgmEntitySchemaComponent } from '@metad/ocap-angular/entity' +import { AppService } from '../../../app.service' +import { ChatbiHomeComponent } from '../home.component' +import { MatButtonModule } from '@angular/material/button' @Component({ standalone: true, @@ -24,6 +27,7 @@ import { NgmEntitySchemaComponent } from '@metad/ocap-angular/entity' ScrollingModule, MatSelectModule, MatIconModule, + MatButtonModule, MatProgressSpinnerModule, DensityDirective, NgmSearchComponent, @@ -39,7 +43,10 @@ export class ChatbiModelsComponent { EntityCapacity = EntityCapacity readonly chatbiService = inject(ChatbiService) + readonly appService = inject(AppService) + readonly homeComponent = inject(ChatbiHomeComponent) + readonly isMobile = this.appService.isMobile readonly search = model('') readonly searchText = computed(() => this.search().trim().toLowerCase()) @@ -71,4 +78,8 @@ export class ChatbiModelsComponent { toggleExpanded(option) { option.expanded =!option.expanded } + + close() { + this.homeComponent.openCubes.set(false) + } } diff --git a/apps/cloud/src/app/features/setting/copilot/basic/basic.component.ts b/apps/cloud/src/app/features/setting/copilot/basic/basic.component.ts index 031948330..b0a9d639a 100644 --- a/apps/cloud/src/app/features/setting/copilot/basic/basic.component.ts +++ b/apps/cloud/src/app/features/setting/copilot/basic/basic.component.ts @@ -57,6 +57,7 @@ export class CopilotBasicComponent extends TranslationBaseComponent { ) readonly models = computed(() => AI_PROVIDERS[this.provider()]?.models || []) readonly secondaryModels = computed(() => AI_PROVIDERS[this.secondaryProvider()]?.models || []) + readonly organizationId = toSignal(this.#store.selectOrganizationId()) readonly saving = signal(false) @@ -90,7 +91,7 @@ export class CopilotBasicComponent extends TranslationBaseComponent { super() effect(() => { - const items = this.copilotService.copilots()?.filter((item) => item.organizationId === this.#store.organizationId) + const items = this.copilotService.copilots()?.filter((item) => item.organizationId === this.organizationId()) this.formGroup.reset() if (items) { const primary = items.find(({ role }) => role === AiProviderRole.Primary) diff --git a/apps/cloud/src/assets/i18n/zh-Hans.json b/apps/cloud/src/assets/i18n/zh-Hans.json index f5c8683e5..5a52374d4 100644 --- a/apps/cloud/src/assets/i18n/zh-Hans.json +++ b/apps/cloud/src/assets/i18n/zh-Hans.json @@ -1389,7 +1389,10 @@ "Chart_Pie": "饼图", "NewCalculatedMeasures": "新增计算指标", "RenewTokenLimit": "重置 Token 限制", - "Save": "保存" + "Save": "保存", + "SelectSemanticModel": "选择语义模型", + "SelectCube": "选择一个数据集", + "SelectACube": "选择一个数据集" }, "Home": { "Insight": { diff --git a/libs/apps/indicator-market/src/lib/indicator-detail/indicator-detail.component.ts b/libs/apps/indicator-market/src/lib/indicator-detail/indicator-detail.component.ts index fb98f6632..6aaf29769 100644 --- a/libs/apps/indicator-market/src/lib/indicator-detail/indicator-detail.component.ts +++ b/libs/apps/indicator-market/src/lib/indicator-detail/indicator-detail.component.ts @@ -205,7 +205,8 @@ export class IndicatorDetailComponent { type: TimeRangeType.Standard, granularity: timeGranularity, formatter: level?.semantics?.formatter, - lookBack: period?.lookBack ?? lookBack + lookBack: period?.lookBack ?? lookBack, + lookAhead: 0 }) return { diff --git a/libs/apps/state/src/lib/store.service.ts b/libs/apps/state/src/lib/store.service.ts index bbe0706c7..95c08648a 100644 --- a/libs/apps/state/src/lib/store.service.ts +++ b/libs/apps/state/src/lib/store.service.ts @@ -25,7 +25,6 @@ import { uniqBy } from 'lodash-es'; import { toSignal } from '@angular/core/rxjs-interop'; import { ComponentEnum } from './constants'; import { ThemesEnum, prefersColorScheme } from '@metad/ocap-angular/core'; -import { BusinessRoleType } from '@metad/copilot'; export interface AppState { diff --git a/packages/core/src/lib/services/indicator-data.service.ts b/packages/core/src/lib/services/indicator-data.service.ts index 5ae216209..fe6da080f 100644 --- a/packages/core/src/lib/services/indicator-data.service.ts +++ b/packages/core/src/lib/services/indicator-data.service.ts @@ -143,7 +143,8 @@ export class SmartIndicatorDataService< type: TimeRangeType.Standard, granularity: this.currentTime?.timeGranularity, formatter: this.calendarLevel.semantics?.formatter, - lookBack + lookBack, + lookAhead: 0 }) } else { throw new Error(`Can't found calendar level in ${this.calendarHierarchy.name}`)