Skip to content

Commit

Permalink
Merge pull request #10 from xpert-ai/develop
Browse files Browse the repository at this point in the history
Version 3.0.1
  • Loading branch information
tiven-w authored Dec 7, 2024
2 parents 383372d + 4b94ba0 commit 8c68f59
Show file tree
Hide file tree
Showing 180 changed files with 8,180 additions and 807 deletions.
1 change: 1 addition & 0 deletions .deploy/webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"short-unique-id": "^4.4.4",
"socket.io-client": "^4.7.5",
"sql-formatter": "^4.0.2",
"swagger-ui": "^5.18.2",
"swiper": "^8.0.7",
"timers": "^0.1.1",
"tinymce": "^6.0.0",
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/storybook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ jobs:
persist-credentials: false
- name: Install and Build 🔧
run: | # Install npm packages and build the Storybook files
npm install --legacy-peer-deps
npm run b:docs
yarn bootstrap
yarn b:docs
mv dist/storybook/angular docs/storybook
mv packages/core/.docs docs/api/core
mv packages/store/.docs docs/api/store
Expand Down
3 changes: 2 additions & 1 deletion apps/cloud/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@
"packages/angular/_index.scss",
"packages/copilot-angular/_index.scss",
"apps/cloud/src/styles.scss",
"node_modules/@ctrl/ngx-emoji-mart/picker.css"
"node_modules/@ctrl/ngx-emoji-mart/picker.css",
"node_modules/swagger-ui/dist/swagger-ui.css"
],
"stylePreprocessorOptions": {
"includePaths": ["node_modules/"]
Expand Down
10 changes: 10 additions & 0 deletions apps/cloud/src/app/@core/services/api-key.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Injectable } from '@angular/core'
import { API_PREFIX, OrganizationBaseCrudService } from '@metad/cloud/state'
import { IApiKey } from '../types'

@Injectable({ providedIn: 'root' })
export class ApiKeyService extends OrganizationBaseCrudService<IApiKey> {
constructor() {
super(API_PREFIX + '/api-key')
}
}
50 changes: 11 additions & 39 deletions apps/cloud/src/app/@core/services/chat.service.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,21 @@
import { Injectable, inject } from '@angular/core'
import { Store } from '@metad/cloud/state'
import { TChatOptions, TChatRequest } from '../types'
import { EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source'
import { Observable } from 'rxjs'
import { AuthStrategy } from '../auth'
import { Injectable } from '@angular/core'
import { API_CHAT } from '../constants/app.constants'
import { injectApiBaseUrl } from '../providers'
import { TChatOptions, TChatRequest } from '../types'
import { injectFetchEventSource } from './fetch-event-source'

@Injectable({ providedIn: 'root' })
export class ChatService {
readonly #store = inject(Store)
readonly #auth = inject(AuthStrategy)
readonly baseUrl = injectApiBaseUrl()
readonly fetchEventSource = injectFetchEventSource()

chat(request: TChatRequest, options: TChatOptions): Observable<EventSourceMessage> {
const token = this.#store.token
const organization = this.#store.selectedOrganization ?? { id: null }

return new Observable((subscriber) => {
const ctrl = new AbortController()
fetchEventSource(this.baseUrl + API_CHAT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
'Organization-Id': `${organization.id}`
},
body: JSON.stringify({
request,
options
}),
signal: ctrl.signal,
onmessage(msg) {
subscriber.next(msg)
},
onclose() {
subscriber.complete()
},
onerror(err) {
subscriber.error(err)
throw err
}
chat(request: TChatRequest, options: TChatOptions) {
return this.fetchEventSource(
this.baseUrl + API_CHAT,
JSON.stringify({
request,
options
})

return () => ctrl.abort()
})
)
}
}
65 changes: 65 additions & 0 deletions apps/cloud/src/app/@core/services/fetch-event-source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { inject } from '@angular/core'
import { EventSourceMessage, EventStreamContentType, fetchEventSource } from '@microsoft/fetch-event-source'
import { firstValueFrom, Observable } from 'rxjs'
import { AuthStrategy } from '../auth'
import { Store } from './store.service'

export function injectFetchEventSource<T extends BodyInit | null>() {
const store = inject(Store)
const auth = inject(AuthStrategy)

return (url: string, data: T) => {
const token = store.token
const organization = store.selectedOrganization ?? { id: null }

return new Observable<EventSourceMessage>((subscriber) => {
const ctrl = new AbortController()

let unauthorized = false
function req() {
fetchEventSource(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
'Organization-Id': `${organization.id}`
},
body: data,
signal: ctrl.signal,
onopen: async (response) => {
if (!unauthorized && response.status === 401) {
unauthorized = true
await firstValueFrom(auth.refreshToken())
return req()
}

const contentType = response.headers.get('content-type')
if (
!(contentType === null || contentType === void 0
? void 0
: contentType.startsWith(EventStreamContentType))
) {
throw new Error(`Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}`)
}
},
onmessage(msg) {
subscriber.next(msg)
},
onclose() {
if (!unauthorized) {
subscriber.complete()
}
},
onerror(err) {
subscriber.error(err)
throw err
}
})
}

req()

return () => ctrl.abort()
})
}
}
3 changes: 2 additions & 1 deletion apps/cloud/src/app/@core/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ export * from './xpert-workspace.service'
export * from './xpert-agent.service'
export * from './xpert-agent-execution.service'
export * from './copilot-provider.service'
export * from './copilot-server.service'
export * from './copilot-server.service'
export * from './api-key.service'
43 changes: 8 additions & 35 deletions apps/cloud/src/app/@core/services/xpert-agent.service.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,29 @@
import { inject, Injectable } from '@angular/core'
import { EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source'
import { pick } from 'lodash-es'
import { NGXLogger } from 'ngx-logger'
import { BehaviorSubject, Observable } from 'rxjs'
import { BehaviorSubject } from 'rxjs'
import { API_XPERT_AGENT } from '../constants/app.constants'
import { injectApiBaseUrl } from '../providers'
import { IXpertAgent, TChatAgentParams } from '../types'
import { Store } from './store.service'
import { XpertWorkspaceBaseCrudService } from './xpert-workspace.service'
import { injectFetchEventSource } from './fetch-event-source'

@Injectable({ providedIn: 'root' })
export class XpertAgentService extends XpertWorkspaceBaseCrudService<IXpertAgent> {
readonly #logger = inject(NGXLogger)
readonly #store = inject(Store)
readonly baseUrl = injectApiBaseUrl()
readonly fetchEventSource = injectFetchEventSource()

readonly #refresh = new BehaviorSubject<void>(null)

constructor() {
super(API_XPERT_AGENT)
}

chatAgent(data: TChatAgentParams): Observable<EventSourceMessage> {
const token = this.#store.token
const organization = this.store.selectedOrganization ?? { id: null }
return new Observable((subscriber) => {
const ctrl = new AbortController()
fetchEventSource(this.baseUrl + this.apiBaseUrl + `/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
'Organization-Id': `${organization.id}`
},
body: JSON.stringify({
...data,
xpert: pick(data.xpert, 'id', 'name', 'copilotId', 'copilotModel')
}),
signal: ctrl.signal,
onmessage(msg) {
subscriber.next(msg)
},
onclose() {
subscriber.complete()
},
onerror(err) {
subscriber.error(err)
throw err
}
})

return () => ctrl.abort()
})
chatAgent(data: TChatAgentParams) {
return this.fetchEventSource(this.baseUrl + this.apiBaseUrl + `/chat`, JSON.stringify({
...data,
xpert: pick(data.xpert, 'id', 'name', 'copilotId', 'copilotModel')
}))
}
}
38 changes: 6 additions & 32 deletions apps/cloud/src/app/@core/services/xpert.service.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { inject, Injectable } from '@angular/core'
import { PaginationParams, Store, toHttpParams } from '@metad/cloud/state'
import { PaginationParams, toHttpParams } from '@metad/cloud/state'
import { toParams } from '@metad/ocap-angular/core'
import { EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source'
import { NGXLogger } from 'ngx-logger'
import { BehaviorSubject, Observable, tap } from 'rxjs'
import { BehaviorSubject, tap } from 'rxjs'
import { API_XPERT_ROLE } from '../constants/app.constants'
import { IUser, IXpert, IXpertAgentExecution, OrderTypeEnum, TChatRequest, TXpertTeamDraft, XpertTypeEnum } from '../types'
import { XpertWorkspaceBaseCrudService } from './xpert-workspace.service'
import { injectApiBaseUrl } from '../providers'
import { injectFetchEventSource } from './fetch-event-source'

@Injectable({ providedIn: 'root' })
export class XpertService extends XpertWorkspaceBaseCrudService<IXpert> {
readonly #logger = inject(NGXLogger)
readonly #store = inject(Store)
readonly baseUrl = injectApiBaseUrl()
readonly fetchEventSource = injectFetchEventSource()

readonly #refresh = new BehaviorSubject<void>(null)

Expand Down Expand Up @@ -67,34 +67,8 @@ export class XpertService extends XpertWorkspaceBaseCrudService<IXpert> {
return this.httpClient.get<{items: IXpertAgentExecution[]}>(this.apiBaseUrl + `/${id}/executions`, { params: toHttpParams(options) })
}

chat(id: string, request: TChatRequest, options: { isDraft: boolean; }): Observable<EventSourceMessage> {
const token = this.#store.token
const organization = this.store.selectedOrganization ?? { id: null }
return new Observable((subscriber) => {
const ctrl = new AbortController()
fetchEventSource(this.baseUrl + this.apiBaseUrl + `/${id}/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
'Organization-Id': `${organization.id}`
},
body: JSON.stringify({request, options}),
signal: ctrl.signal,
onmessage(msg) {
subscriber.next(msg)
},
onclose() {
subscriber.complete()
},
onerror(err) {
subscriber.error(err)
throw err; // rethrow to stop the operation, otherwise do nothing to automatically retry.
}
})

return () => ctrl.abort()
})
chat(id: string, request: TChatRequest, options: { isDraft: boolean; }) {
return this.fetchEventSource(this.baseUrl + this.apiBaseUrl + `/${id}/chat`, JSON.stringify({request, options}))
}

getXpertManagers(id: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,19 @@

<div class="relative">
<div class="px-4 pt-2 bg-white rounded-t-xl text-sm text-gray-700 overflow-y-auto"
[style.height.px]="height">
<div class="relative min-h-5">
<div #editablePrompt
class="outline-none leading-5 text-sm whitespace-pre-wrap break-words text-gray-700"
contenteditable="true"
role="textbox"
spellcheck="true"
(blur)="onPromptChange(editablePrompt)"
ngmHighlightVar
[regex]="regex"
[content]="prompt()"
customClasses="inline-block text-primary-500 bg-transparent"
>
</div>
[style.height.px]="height"
>
<div #editablePrompt
class="h-full outline-none leading-5 text-sm whitespace-pre-wrap break-words text-gray-700"
contenteditable="true"
role="textbox"
spellcheck="true"
(blur)="onPromptChange(editablePrompt)"
ngmHighlightVar
[regex]="regex"
[content]="prompt()"
customClasses="inline-block text-primary-500 bg-transparent"
>
</div>
</div>
<div class="pl-4 pb-2 flex bg-white rounded-b-xl">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CdkMenuModule } from '@angular/cdk/menu'
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, computed, HostListener, inject, input, model } from '@angular/core'
import { ChangeDetectionStrategy, Component, computed, ElementRef, HostListener, inject, input, model, viewChild } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { MatDialog } from '@angular/material/dialog'
import { MatTooltipModule } from '@angular/material/tooltip'
Expand All @@ -24,6 +24,7 @@ export class CopilotPromptEditorComponent {

readonly initHeight = input<number>(210)
readonly tooltip = input<string>()

readonly prompt = model<string>()
readonly promptLength = computed(() => this.prompt()?.length)

Expand All @@ -45,10 +46,9 @@ export class CopilotPromptEditorComponent {
})
}

onBlur() {}
onPromptChange(editor: HTMLDivElement) {
console.log(editor.innerHTML)
console.log(formatInnerHTML(editor.innerHTML))
// console.log(editor.innerHTML)
// console.log(formatInnerHTML(editor.innerHTML))
this.prompt.set(formatInnerHTML(editor.innerHTML))
}

Expand Down
Loading

0 comments on commit 8c68f59

Please sign in to comment.