1
1
let aborter = new AbortController ( ) ;
2
+ let autoAbortTimeout = null ;
2
3
3
4
const outputRef = document . querySelector ( "#outputRef" ) ;
4
5
const loadingRef = document . querySelector ( "#loadingRef" ) ;
@@ -27,47 +28,63 @@ submitQueryRef
27
28
cancelQueryRef . classList . remove ( "hidden" ) ;
28
29
submitQueryRef . classList . add ( "hidden" ) ;
29
30
30
- const stream = await submitQuery ( value ) ;
31
- loadingRef . classList . add ( "hidden" ) ;
31
+ autoTimeout ( ) ;
32
+ submitQuery ( value , insertText ) ;
33
+ }
34
+ } ) ;
32
35
33
- outputRef . innerHTML = "" ;
34
- outputRef . classList . remove ( "hidden" ) ;
36
+ function autoTimeout ( ) {
37
+ autoAbortTimeout = setTimeout ( ( ) => {
38
+ cancelQueryRef . click ( ) ;
35
39
36
- for await ( const chunk of stream ) {
37
- if ( aborter . signal . aborted ) throw signal . reason ;
38
- insertText ( chunk ) ( ) ;
39
- }
40
+ if ( outputRef . innerHTML === "" ) {
41
+ outputRef . innerHTML = "Your Assistant could not fetch data. Please try again!"
42
+ }
40
43
41
- cancelQueryRef . classList . add ( "hidden" ) ;
42
- submitQueryRef . classList . remove ( "hidden" ) ;
43
- loadingRef . classList . add ( "hidden" ) ;
44
+ } , 30_000 ) ; // in case, cancel request after 30 of timeout
44
45
45
- if ( outputRef . innerHTML === "" ) {
46
- outputRef . innerHTML = "Your Assistant could not fetch data. Please try again!"
47
- }
48
- }
49
- } ) ;
46
+ }
50
47
51
- const insertText = chunk => ( ) => {
48
+ function insertText ( chunk ) {
52
49
const delta = new TextDecoder ( ) . decode ( chunk ) ;
53
50
outputRef . innerHTML += delta ;
54
51
outputRef . scrollTop = outputRef . scrollHeight ; // scroll to bottom
55
52
} ;
56
53
57
54
58
- async function submitQuery ( userQuery ) {
55
+ function submitQuery ( userQuery , cb ) {
59
56
60
57
const { API_URL = 'http://localhost:7071' } = import . meta. env ;
61
58
62
- const response = await fetch ( `${ API_URL } /api/assistant` , {
59
+ fetch ( `${ API_URL } /api/assistant` , {
63
60
method : "POST" ,
64
61
body : userQuery ,
65
62
signal : aborter . signal
66
- } ) ;
63
+ } ) . then ( response => response . body )
64
+ . then ( rs => processReadableStream ( rs , cb ) ) ;
65
+ }
67
66
68
- if ( ! response . ok ) {
69
- console . log ( response . statusText ) ;
70
- }
67
+ function processReadableStream ( rs , cb ) {
71
68
72
- return response . body ;
73
- }
69
+ rs . pipeTo ( new WritableStream ( {
70
+ write ( chunk , controller ) {
71
+ cb ( chunk ) ;
72
+ } ,
73
+ start ( controller ) {
74
+ outputRef . innerHTML = "" ;
75
+ loadingRef . classList . add ( "hidden" ) ;
76
+ outputRef . classList . remove ( "hidden" ) ;
77
+ clearTimeout ( autoAbortTimeout ) ; // cancel
78
+ } ,
79
+ close ( controller ) {
80
+ cancelQueryRef . classList . add ( "hidden" ) ;
81
+ submitQueryRef . classList . remove ( "hidden" ) ;
82
+ loadingRef . classList . add ( "hidden" ) ;
83
+ } ,
84
+ abort ( reason ) {
85
+ console . log ( reason ) ;
86
+ } ,
87
+ } ) ) . catch ( console . error ) ;
88
+
89
+ return rs ;
90
+ }
0 commit comments