Show still thinking for slow responses

This commit is contained in:
shamoon committed 2026-10-11 14:00:09 -07:00
1 parent 5edeb3becd
commit 77b6027aa1
3 files changed
+36 -1

No files matched your search

@@ -12,7 +12,11 @@
@if (message.isStreaming && !message.content) {
<div class="d-flex align-items-center text-muted">
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
<ng-container i18n>Thinking...</ng-container>
@if (slowResponse()) {
<ng-container i18n>Still thinking...</ng-container>
} @else {
<ng-container i18n>Thinking...</ng-container>
}
</div>
} @else if (message.role === 'assistant') {
<div class="chat-markdown text-break text-wrap" [innerHTML]="message.content | markdown"></div>
@@ -170,6 +170,21 @@ describe('ChatComponent', () => {
expect(component.loading()).toBe(false)
})
it('should show a slow response message while waiting', () => {
component.input.set('Hello')
component.sendMessage()
fixture.detectChanges()
const messagesEl = fixture.nativeElement.querySelector('.chat-messages')
expect(messagesEl.textContent).not.toContain('Still thinking...')
jest.advanceTimersByTime(8000)
fixture.detectChanges()
expect(messagesEl.textContent).toContain('Still thinking...')
mockStream$.next('Hi')
expect(component.slowResponse()).toBe(false)
})
it('should enqueue typewriter chunks correctly', () => {
const message = { content: '', role: 'assistant', isStreaming: true }
component.enqueueTypewriter(null, message as any) // coverage for null
@@ -18,6 +18,8 @@ import {
parseChatResponse,
} from 'src/app/services/chat.service'
const SLOW_RESPONSE_DELAY_MS = 8000
@Component({
selector: 'pngx-chat',
imports: [
@@ -36,6 +38,7 @@ export class ChatComponent implements OnInit {
readonly loading = signal(false)
readonly input = signal('')
readonly documentId = signal<number>(undefined)
readonly slowResponse = signal(false)
private chatService: ChatService = inject(ChatService)
private router: Router = inject(Router)
@@ -45,6 +48,7 @@ export class ChatComponent implements OnInit {
private typewriterBuffer: string[] = []
private typewriterActive = false
private slowResponseTimeout: ReturnType<typeof setTimeout>
public get placeholder(): string {
return this.documentId()
@@ -83,11 +87,16 @@ export class ChatComponent implements OnInit {
}
this.messages.update((messages) => [...messages, assistantMessage])
this.loading.set(true)
this.slowResponseTimeout = setTimeout(
() => this.slowResponse.set(true),
SLOW_RESPONSE_DELAY_MS
)
let lastVisibleContent = ''
this.chatService.streamChat(this.documentId(), this.input()).subscribe({
next: (chunk) => {
this.clearSlowResponse()
const nextResponse = parseChatResponse(chunk)
if (nextResponse.content.length < lastVisibleContent.length) {
@@ -105,12 +114,14 @@ export class ChatComponent implements OnInit {
this.notifyMessagesChanged()
},
error: () => {
this.clearSlowResponse()
assistantMessage.content += '\n\n⚠️ Error receiving response.'
assistantMessage.isStreaming = false
this.notifyMessagesChanged()
this.loading.set(false)
},
complete: () => {
this.clearSlowResponse()
assistantMessage.isStreaming = false
this.notifyMessagesChanged()
this.loading.set(false)
@@ -121,6 +132,11 @@ export class ChatComponent implements OnInit {
this.input.set('')
}
private clearSlowResponse(): void {
clearTimeout(this.slowResponseTimeout)
this.slowResponse.set(false)
}
private resetTypewriter(message: ChatMessage, content: string): void {
this.typewriterBuffer = []
this.typewriterActive = false