Skip to content

Commit 7fb65e4

Browse files
feat(assistant): displaying annotations in the conversation
1 parent cc8f0d0 commit 7fb65e4

27 files changed

+302
-43
lines changed

apps/spa/src/app/app.config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@ import { routes } from './app.routes';
55
import { provideAnimations } from '@angular/platform-browser/animations';
66
import { provideHttpClient } from '@angular/common/http';
77
import { provideMarkdown } from 'ngx-markdown';
8-
import { AnnotationPipe } from './pipes/annotation.pipe';
98

109
export const appConfig: ApplicationConfig = {
1110
providers: [
1211
provideRouter(routes),
1312
provideAnimations(),
1413
provideHttpClient(),
1514
provideMarkdown(),
16-
AnnotationPipe,
1715
],
1816
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div
2+
class="annotation"
3+
(mouseover)="showDetails()"
4+
[matTooltip]="fileDetails ? fileDetails.filename : 'Reading data...'"
5+
matTooltipPosition="above">
6+
[{{ index }}]
7+
</div>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@import 'settings';
2+
3+
.annotation {
4+
cursor: pointer;
5+
6+
&:hover {
7+
background-color: rgba(0, 0, 0, 0.15);
8+
}
9+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { ChatAnnotationComponent } from './chat-annotation.component';
3+
import { HttpClientTestingModule } from '@angular/common/http/testing';
4+
5+
describe('ChatAnnotationComponent', () => {
6+
let component: ChatAnnotationComponent;
7+
let fixture: ComponentFixture<ChatAnnotationComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [
12+
ChatAnnotationComponent,
13+
HttpClientTestingModule,
14+
],
15+
}).compileComponents();
16+
17+
fixture = TestBed.createComponent(ChatAnnotationComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Component, Input } from '@angular/core';
2+
import { MatTooltip } from '@angular/material/tooltip';
3+
import { Annotation } from 'openai/resources/beta/threads';
4+
import { ChatClientService } from '../../../modules/+chat/shared/chat-client.service';
5+
import { FileObject } from 'openai/resources';
6+
import { isFileCitation } from '../../../pipes/annotation.pipe';
7+
import { take } from 'rxjs';
8+
9+
@Component({
10+
selector: 'ai-chat-annotation',
11+
standalone: true,
12+
templateUrl: './chat-annotation.component.html',
13+
styleUrl: './chat-annotation.component.scss',
14+
imports: [MatTooltip],
15+
})
16+
export class ChatAnnotationComponent {
17+
@Input() annotation!: Annotation;
18+
@Input() index = 1;
19+
fileDetails!: FileObject;
20+
21+
get fileId(): string {
22+
return isFileCitation(this.annotation)
23+
? this.annotation.file_citation.file_id
24+
: this.annotation.file_path.file_id;
25+
}
26+
27+
constructor(private chatClientService: ChatClientService) {}
28+
29+
showDetails() {
30+
if (!this.fileId || !!this.fileDetails) {
31+
return;
32+
}
33+
34+
this.chatClientService
35+
.retriveFile(this.fileId)
36+
.pipe(take(1))
37+
.subscribe(details => (this.fileDetails = details));
38+
}
39+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@if (message && message.type === 'text' && message.text.annotations.length) {
2+
<div class="title">Annotations:</div>
3+
<div class="content">
4+
@for (annotation of message.text.annotations; track annotation.text) {
5+
<ai-chat-annotation [annotation]="annotation" [index]="$index + 1">
6+
[{{ $index + 1 }}]
7+
</ai-chat-annotation>
8+
}
9+
</div>
10+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
@import 'settings';
2+
3+
:host {
4+
display: flex;
5+
align-items: baseline;
6+
gap: $size-2;
7+
border-top: 1px dashed var(--color-grey-500);
8+
margin-top: $size-3;
9+
padding-top: $size-3;
10+
font-size: 12px;
11+
12+
&:empty {
13+
display: none;
14+
}
15+
}
16+
17+
.title {
18+
font-weight: 500;
19+
}
20+
21+
.content {
22+
display: flex;
23+
gap: $size-1;
24+
margin-top: $size-2;
25+
}
26+
27+
.annotation {
28+
cursor: pointer;
29+
30+
&:hover {
31+
background-color: rgba(0, 0, 0, 0.15);
32+
}
33+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { MarkdownModule } from 'ngx-markdown';
3+
import { ChatAnnotationsComponent } from './chat-annotations.component';
4+
5+
describe('ChatAnnotationsComponent', () => {
6+
let component: ChatAnnotationsComponent;
7+
let fixture: ComponentFixture<ChatAnnotationsComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [ChatAnnotationsComponent, MarkdownModule.forRoot()],
12+
}).compileComponents();
13+
14+
fixture = TestBed.createComponent(ChatAnnotationsComponent);
15+
component = fixture.componentInstance;
16+
fixture.detectChanges();
17+
});
18+
19+
it('should create', () => {
20+
expect(component).toBeTruthy();
21+
});
22+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Component, Input } from '@angular/core';
2+
import { MatTooltip } from '@angular/material/tooltip';
3+
import { MessageContent } from 'openai/resources/beta/threads';
4+
import { ChatAnnotationComponent } from '../chat-annotation/chat-annotation.component';
5+
6+
@Component({
7+
selector: 'ai-chat-annotations',
8+
standalone: true,
9+
templateUrl: './chat-annotations.component.html',
10+
styleUrl: './chat-annotations.component.scss',
11+
imports: [MatTooltip, ChatAnnotationComponent],
12+
})
13+
export class ChatAnnotationsComponent {
14+
@Input() message!: MessageContent;
15+
}

apps/spa/src/app/components/chat/chat-message/chat-message.component.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
}
55

66
<div class="chat-message">
7-
@if (message | messageText) {
8-
<span markdown [data]="message | messageText"></span>
7+
@for (msg of message.content; track msg) {
8+
@if (msg.type === 'text') {
9+
<span markdown [data]="msg | annotation"></span>
10+
}
11+
<ai-chat-annotations [message]="msg" />
912
}
1013

1114
@if ((message | messageImageFile).length) {

0 commit comments

Comments
 (0)