Skip to content

Commit

Permalink
feat: demo page with navbar (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianmusial committed Mar 15, 2024
1 parent e3ac46c commit 73196c9
Show file tree
Hide file tree
Showing 27 changed files with 319 additions and 131 deletions.
6 changes: 2 additions & 4 deletions .commitlintrc.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module.exports = {
extends: [
'@commitlint/config-conventional',
],
extends: ['@commitlint/config-conventional'],
rules: {
'header-max-length': [0, 'always', 120],
}
},
};
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,12 @@ export class ChatModule {}

The repository includes a library with an AI assistant as well as other useful parts:

| Name | Type | Description |
| ----------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `@boldare/ai-assistant` | `library` | A NestJS library based on the OpenAI Assistant for building efficient, scalable, and quick solutions for AI assistants/chatbots |
| `@boldare/ai-embedded` | `library` | The code enables embedding the chatbot on various websites through JavaScript scripts. |
| `api` | `application` | Example usage of the `@boldare/ai-assistant` library. |
| `spa` | `application` | Example client application (SPA) with a chatbot. |
| Name | Description | More |
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| `@boldare/ai-assistant` | A NestJS library based on the OpenAI Assistant for building efficient, scalable, and quick solutions for AI assistants/chatbots | [Documentation](https://github.com/boldare/ai-assistant/wiki/%F0%9F%A4%96-AI-Assistant) |
| `@boldare/ai-embedded` | The code enables embedding the chatbot on various websites through JavaScript scripts. | [Documentation](https://github.com/boldare/ai-assistant/wiki/%F0%9F%96%87-Integrating-Chatbot-into-Your-Website) |
| `api` | Example usage of the `@boldare/ai-assistant` library. | [Documentation](https://github.com/boldare/ai-assistant/wiki/%F0%9F%91%A8%E2%80%8D%F0%9F%92%BB-Repository) |
| `spa` | Example client application (SPA) with a chatbot. | [Documenation](https://github.com/boldare/ai-assistant/wiki/%F0%9F%92%AC-Chatbot-%E2%80%90-Client-application) |

## Getting started

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ChatIframeWrapperComponent } from './chat-iframe-wrapper.component';

describe('ChatIframeWrapperComponent', () => {
let component: ChatIframeWrapperComponent;
let fixture: ComponentFixture<ChatIframeWrapperComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ChatIframeWrapperComponent],
}).compileComponents();

fixture = TestBed.createComponent(ChatIframeWrapperComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';

@Component({
selector: 'ai-chat-iframe-wrapper',
standalone: true,
templateUrl: './chat-iframe-wrapper.component.html',
styleUrl: './chat-iframe-wrapper.component.scss',
})
export class ChatIframeWrapperComponent {}

This file was deleted.

26 changes: 21 additions & 5 deletions apps/spa/src/app/modules/+chat/chat.routes.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
import { Routes } from '@angular/router';
import { ChatComponent } from './containers/chat/chat.component';

export const routes: Routes = [
{
path: '',
loadComponent: () =>
import('./containers/chat-example/chat-example.component').then(
mod => mod.ChatExampleComponent,
),
component: ChatComponent,
children: [
{
path: '',
loadComponent: () =>
import('./containers/chat-home/chat-home.component').then(
mod => mod.ChatHomeComponent,
),
},
{
path: 'integration',
loadComponent: () =>
import(
'./containers/chat-integration/chat-integration.component'
).then(mod => mod.ChatIntegrationComponent),
},
],
},
{
path: 'iframe',
loadComponent: () =>
import('./containers/chat/chat.component').then(mod => mod.ChatComponent),
import('./containers/chat-iframe/chat-iframe.component').then(
mod => mod.ChatIframeComponent,
),
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
A NestJS library for building efficient, scalable, and quick solutions based on
the OpenAI Assistant API (chatbots) 🤖 🚀
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
:host {
max-width: 600px;
margin-top: 40px;
color: var(--color-grey-600);
font-size: 18px;
text-align: center;
letter-spacing: 0.03em;
line-height: 1.6;
font-weight: 300;
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ChatExampleComponent } from './chat-example.component';
import { ChatHomeComponent } from './chat-home.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { MarkdownModule } from 'ngx-markdown';

describe('ChatExampleComponent', () => {
let component: ChatExampleComponent;
let fixture: ComponentFixture<ChatExampleComponent>;
describe('ChatHomeComponent', () => {
let component: ChatHomeComponent;
let fixture: ComponentFixture<ChatHomeComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
ChatExampleComponent,
ChatHomeComponent,
HttpClientTestingModule,
MarkdownModule.forRoot(),
],
}).compileComponents();

fixture = TestBed.createComponent(ChatExampleComponent);
fixture = TestBed.createComponent(ChatHomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';

@Component({
selector: 'ai-chat-home',
standalone: true,
templateUrl: './chat-home.component.html',
styleUrl: './chat-home.component.scss',
})
export class ChatHomeComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<ai-card class="chat">
<ai-chat-header
[isRefreshEnabled]="isRefreshEnabled && !!threadId()"
[isConfigEnabled]="isConfigEnabled && !!threadId()"
(refresh$)="chatService.refresh()"
(close$)="chatService.toggle()"
(config$)="chatService.clear()"></ai-chat-header>

<ai-spinner [isActive]="isLoading()" />
@if (isConfigEnabled && !threadId()) {
<ai-configuration-form class="chat__content" />
} @else {
<ai-chat-messages
[messages]="messages()"
[isTyping]="isTyping()"
[tips]="tips"
(tipSelected$)="chatService.sendMessage($event)"
class="chat__content" />
<ai-chat-footer
[isDisabled]="isTyping()"
[isTranscriptionEnabled]="isTranscriptionEnabled"
[isAttachmentEnabled]="isAttachmentEnabled"
(sendMessage$)="chatService.sendMessage($event)"
(sendAudio$)="chatService.sendAudio($event)" />
}
</ai-card>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
:host {
display: flex;
height: 100vh;
max-height: 600px;
background-color: var(--color-white);
border-radius: var(--border-radius-medium);
}

.chat {
display: flex;
flex-direction: column;
}

.chat__content {
flex: 1 1 100%;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ChatIframeComponent } from './chat-iframe.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';

describe('ChatIframeComponent', () => {
let component: ChatIframeComponent;
let fixture: ComponentFixture<ChatIframeComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ChatIframeComponent],
imports: [
HttpClientTestingModule,
BrowserAnimationsModule,
ChatIframeComponent,
RouterTestingModule,
],
}).compileComponents();

fixture = TestBed.createComponent(ChatIframeComponent);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Component, OnInit } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { environment } from '../../../../../environments/environment';
import { ChatService } from '../../shared/chat.service';
import { ThreadService } from '../../shared/thread.service';
import { CardComponent } from '../../../../components/cards';
import { ChatHeaderComponent } from '../../../../components/chat/chat-header/chat-header.component';
import { ChatMessagesComponent } from '../../../../components/chat/chat-messages/chat-messages.component';
import { ChatFooterComponent } from '../../../../components/chat/chat-footer/chat-footer.component';
import { ConfigurationFormComponent } from '../../../+configuration/components/configuration-form/configuration-form.component';
import { take } from 'rxjs';
import { SpinnerComponent } from '../../../../components/spinner/spinner.component';

@Component({
selector: 'ai-chat-iframe',
standalone: true,
imports: [
CardComponent,
ChatHeaderComponent,
ChatMessagesComponent,
ChatFooterComponent,
ConfigurationFormComponent,
SpinnerComponent,
],
templateUrl: './chat-iframe.component.html',
styleUrl: './chat-iframe.component.scss',
})
export class ChatIframeComponent implements OnInit {
messages = toSignal(this.chatService.messages$, { initialValue: [] });
isTyping = toSignal(this.chatService.isTyping$, { initialValue: false });
isLoading = toSignal(this.chatService.isLoading$, { initialValue: false });
threadId = toSignal(this.threadService.threadId$, { initialValue: '' });
isTranscriptionEnabled = environment.isTranscriptionEnabled;
isAttachmentEnabled = environment.isAttachmentEnabled;
isRefreshEnabled = environment.isRefreshEnabled;
isConfigEnabled = environment.isConfigEnabled;
tips = [
'Hello there! 👋',
'Could you please tell me your name?',
'Hello! How can you help me?',
'Hello! 👋 How are you?',
];

constructor(
private readonly threadService: ThreadService,
public readonly chatService: ChatService,
) {}

ngOnInit() {
if (!this.isConfigEnabled && !this.threadService.threadId$.value) {
this.threadService.start().pipe(take(1)).subscribe();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ChatIntegrationComponent } from './chat-integration.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { MarkdownModule } from 'ngx-markdown';

describe('ChatIntegrationComponent', () => {
let component: ChatIntegrationComponent;
let fixture: ComponentFixture<ChatIntegrationComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
ChatIntegrationComponent,
HttpClientTestingModule,
MarkdownModule.forRoot(),
],
}).compileComponents();

fixture = TestBed.createComponent(ChatIntegrationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { Component } from '@angular/core';
import { AssistantIframe } from '@boldare/ai-embedded';
import { AsyncPipe } from '@angular/common';
import { ChatService } from '../../shared/chat.service';
import { environment } from '../../../../../environments/environment';
import { MarkdownComponent, MarkdownPipe } from 'ngx-markdown';

@Component({
selector: 'ai-chat-example',
selector: 'ai-chat-integration',
standalone: true,
templateUrl: './chat-example.component.html',
styleUrl: './chat-example.component.scss',
templateUrl: './chat-integration.component.html',
styleUrl: './chat-integration.component.scss',
imports: [MarkdownComponent, MarkdownPipe, AsyncPipe],
})
export class ChatExampleComponent {
export class ChatIntegrationComponent {
scriptMarkdown = `\`\`\`html
<script
src="${environment.appUrl}/assets/js/ai-embedded.js"
Expand All @@ -30,12 +28,4 @@ new AssistantIframe({
url: \`${environment.appUrl}/chat/iframe\`
}).init();
\`\`\``;

constructor(private readonly chatService: ChatService) {
if (environment.env === 'prod') {
this.chatService.loadScript();
} else {
new AssistantIframe().init();
}
}
}
Loading

0 comments on commit 73196c9

Please sign in to comment.