From 51c47707bb0b18f769b6b5963702199c382212b6 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 25 Apr 2025 19:38:43 -0700 Subject: [PATCH] Try rewriting with httpclient --- .../src/app/interceptors/csrf.interceptor.ts | 14 +++- src-ui/src/app/services/chat.service.ts | 71 ++++++++----------- src-ui/src/app/services/csrf.service.ts | 23 ------ src-ui/src/main.ts | 3 +- 4 files changed, 42 insertions(+), 69 deletions(-) delete mode 100644 src-ui/src/app/services/csrf.service.ts diff --git a/src-ui/src/app/interceptors/csrf.interceptor.ts b/src-ui/src/app/interceptors/csrf.interceptor.ts index e9c59ac8e..2febf2014 100644 --- a/src-ui/src/app/interceptors/csrf.interceptor.ts +++ b/src-ui/src/app/interceptors/csrf.interceptor.ts @@ -5,18 +5,26 @@ import { HttpRequest, } from '@angular/common/http' import { Injectable } from '@angular/core' +import { Meta } from '@angular/platform-browser' +import { CookieService } from 'ngx-cookie-service' import { Observable } from 'rxjs' -import { CsrfService } from '../services/csrf.service' @Injectable() export class CsrfInterceptor implements HttpInterceptor { - constructor(private csrfService: CsrfService) {} + constructor( + private cookieService: CookieService, + private meta: Meta + ) {} intercept( request: HttpRequest, next: HttpHandler ): Observable> { - const csrfToken = this.csrfService.getToken() + let prefix = '' + if (this.meta.getTag('name=cookie_prefix')) { + prefix = this.meta.getTag('name=cookie_prefix').content + } + let csrfToken = this.cookieService.get(`${prefix}csrftoken`) if (csrfToken) { request = request.clone({ setHeaders: { diff --git a/src-ui/src/app/services/chat.service.ts b/src-ui/src/app/services/chat.service.ts index b32efbc39..5e576ceba 100644 --- a/src-ui/src/app/services/chat.service.ts +++ b/src-ui/src/app/services/chat.service.ts @@ -1,7 +1,11 @@ +import { + HttpClient, + HttpDownloadProgressEvent, + HttpEventType, +} from '@angular/common/http' import { Injectable } from '@angular/core' -import { Observable } from 'rxjs' +import { filter, map, Observable } from 'rxjs' import { environment } from 'src/environments/environment' -import { CsrfService } from './csrf.service' export interface ChatMessage { role: 'user' | 'assistant' @@ -13,48 +17,31 @@ export interface ChatMessage { providedIn: 'root', }) export class ChatService { - constructor(private csrfService: CsrfService) {} + constructor(private http: HttpClient) {} streamChat(documentId: number, prompt: string): Observable { - return new Observable((observer) => { - const url = `${environment.apiBaseUrl}documents/chat/` - const xhr = new XMLHttpRequest() - let lastLength = 0 - - xhr.open('POST', url) - xhr.setRequestHeader('Content-Type', 'application/json') - - xhr.withCredentials = true - let csrfToken = this.csrfService.getToken() - if (csrfToken) { - xhr.setRequestHeader('X-CSRFToken', csrfToken) - } - - xhr.onreadystatechange = () => { - if (xhr.readyState === 3 || xhr.readyState === 4) { - const partial = xhr.responseText.slice(lastLength) - lastLength = xhr.responseText.length - - if (partial) { - observer.next(partial) + // use httpclient as we have withFetch + return this.http + .post( + `${environment.apiBaseUrl}documents/chat/`, + { + document_id: documentId, + q: prompt, + }, + { + observe: 'events', + reportProgress: true, + responseType: 'text', + withCredentials: true, + } + ) + .pipe( + map((event) => { + if (event.type === HttpEventType.DownloadProgress) { + return (event as HttpDownloadProgressEvent).partialText! } - } - - if (xhr.readyState === 4) { - observer.complete() - } - } - - xhr.onerror = () => { - observer.error(new Error('Streaming request failed.')) - } - - const body = JSON.stringify({ - document_id: documentId, - q: prompt, - }) - - xhr.send(body) - }) + }), + filter((chunk) => !!chunk) + ) } } diff --git a/src-ui/src/app/services/csrf.service.ts b/src-ui/src/app/services/csrf.service.ts deleted file mode 100644 index 28f5094ac..000000000 --- a/src-ui/src/app/services/csrf.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core' -import { Meta } from '@angular/platform-browser' -import { CookieService } from 'ngx-cookie-service' // Assuming you're using this - -@Injectable({ providedIn: 'root' }) -export class CsrfService { - constructor( - private cookieService: CookieService, - private meta: Meta - ) {} - - public getCookiePrefix(): string { - let prefix = '' - if (this.meta.getTag('name=cookie_prefix')) { - prefix = this.meta.getTag('name=cookie_prefix').content - } - return prefix - } - - public getToken(): string { - return this.cookieService.get(`${this.getCookiePrefix()}csrftoken`) - } -} diff --git a/src-ui/src/main.ts b/src-ui/src/main.ts index 78ec25a67..4191c0ea2 100644 --- a/src-ui/src/main.ts +++ b/src-ui/src/main.ts @@ -9,6 +9,7 @@ import { DatePipe, registerLocaleData } from '@angular/common' import { HTTP_INTERCEPTORS, provideHttpClient, + withFetch, withInterceptorsFromDi, } from '@angular/common/http' import { FormsModule, ReactiveFormsModule } from '@angular/forms' @@ -391,6 +392,6 @@ bootstrapApplication(AppComponent, { CorrespondentNamePipe, DocumentTypeNamePipe, StoragePathNamePipe, - provideHttpClient(withInterceptorsFromDi()), + provideHttpClient(withInterceptorsFromDi(), withFetch()), ], }).catch((err) => console.error(err))