@@ -3,7 +3,7 @@ function gradioApp() {
3
3
const elems = document . getElementsByTagName ( 'gradio-app' ) ;
4
4
const elem = elems . length == 0 ? document : elems [ 0 ] ;
5
5
if ( elem !== document ) {
6
- elem . getElementById = function ( id ) {
6
+ elem . getElementById = function ( id ) {
7
7
return document . getElementById ( id ) ;
8
8
} ;
9
9
}
@@ -12,31 +12,31 @@ function gradioApp() {
12
12
13
13
function setCookie ( name , value , days ) {
14
14
var expires = "" ;
15
-
15
+
16
16
if ( days ) {
17
- var date = new Date ( ) ;
18
- date . setTime ( date . getTime ( ) + ( days * 24 * 60 * 60 * 1000 ) ) ;
19
- expires = "; expires=" + date . toUTCString ( ) ;
17
+ var date = new Date ( ) ;
18
+ date . setTime ( date . getTime ( ) + ( days * 24 * 60 * 60 * 1000 ) ) ;
19
+ expires = "; expires=" + date . toUTCString ( ) ;
20
20
}
21
-
21
+
22
22
document . cookie = name + "=" + value + expires + "; path=/" ;
23
23
}
24
24
25
25
function getCookie ( name ) {
26
26
var decodedCookie = decodeURIComponent ( document . cookie ) ;
27
27
var cookies = decodedCookie . split ( ';' ) ;
28
-
28
+
29
29
for ( var i = 0 ; i < cookies . length ; i ++ ) {
30
- var cookie = cookies [ i ] . trim ( ) ;
31
-
32
- if ( cookie . indexOf ( name + "=" ) === 0 ) {
33
- return cookie . substring ( name . length + 1 , cookie . length ) ;
34
- }
30
+ var cookie = cookies [ i ] . trim ( ) ;
31
+
32
+ if ( cookie . indexOf ( name + "=" ) === 0 ) {
33
+ return cookie . substring ( name . length + 1 , cookie . length ) ;
34
+ }
35
35
}
36
-
36
+
37
37
return null ;
38
- }
39
-
38
+ }
39
+
40
40
function addCopyButton ( botElement ) {
41
41
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
42
42
// Copy bot button
@@ -49,7 +49,7 @@ function addCopyButton(botElement) {
49
49
// messageBtnColumnElement.remove();
50
50
return ;
51
51
}
52
-
52
+
53
53
var copyButton = document . createElement ( 'button' ) ;
54
54
copyButton . classList . add ( 'copy-bot-btn' ) ;
55
55
copyButton . setAttribute ( 'aria-label' , 'Copy' ) ;
@@ -98,40 +98,38 @@ function chatbotContentChanged(attempt = 1, force = false) {
98
98
}
99
99
}
100
100
101
- function chatbotAutoHeight ( ) {
101
+ function chatbotAutoHeight ( ) {
102
102
// 自动调整高度
103
- function update_height ( ) {
103
+ function update_height ( ) {
104
104
var { panel_height_target, chatbot_height, chatbot } = get_elements ( true ) ;
105
- if ( panel_height_target != chatbot_height )
106
- {
105
+ if ( panel_height_target != chatbot_height ) {
107
106
var pixelString = panel_height_target . toString ( ) + 'px' ;
108
- chatbot . style . maxHeight = pixelString ; chatbot . style . height = pixelString ;
107
+ chatbot . style . maxHeight = pixelString ; chatbot . style . height = pixelString ;
109
108
}
110
109
}
111
110
112
- function update_height_slow ( ) {
111
+ function update_height_slow ( ) {
113
112
var { panel_height_target, chatbot_height, chatbot } = get_elements ( ) ;
114
- if ( panel_height_target != chatbot_height )
115
- {
116
- new_panel_height = ( panel_height_target - chatbot_height ) * 0.5 + chatbot_height ;
117
- if ( Math . abs ( new_panel_height - panel_height_target ) < 10 ) {
113
+ if ( panel_height_target != chatbot_height ) {
114
+ new_panel_height = ( panel_height_target - chatbot_height ) * 0.5 + chatbot_height ;
115
+ if ( Math . abs ( new_panel_height - panel_height_target ) < 10 ) {
118
116
new_panel_height = panel_height_target ;
119
117
}
120
118
// console.log(chatbot_height, panel_height_target, new_panel_height);
121
119
var pixelString = new_panel_height . toString ( ) + 'px' ;
122
- chatbot . style . maxHeight = pixelString ; chatbot . style . height = pixelString ;
120
+ chatbot . style . maxHeight = pixelString ; chatbot . style . height = pixelString ;
123
121
}
124
122
}
125
123
monitoring_input_box ( )
126
124
update_height ( ) ;
127
- setInterval ( function ( ) {
125
+ setInterval ( function ( ) {
128
126
update_height_slow ( )
129
127
} , 50 ) ; // 每100毫秒执行一次
130
128
}
131
129
132
130
133
131
134
- function get_elements ( consider_state_panel = false ) {
132
+ function get_elements ( consider_state_panel = false ) {
135
133
var chatbot = document . querySelector ( '#gpt-chatbot > div.wrap.svelte-18telvq' ) ;
136
134
if ( ! chatbot ) {
137
135
chatbot = document . querySelector ( '#gpt-chatbot' ) ;
@@ -142,13 +140,13 @@ function get_elements(consider_state_panel=false) {
142
140
// const panel4 = document.querySelector('#interact-panel').getBoundingClientRect();
143
141
const panel5 = document . querySelector ( '#input-panel2' ) . getBoundingClientRect ( ) ;
144
142
const panel_active = document . querySelector ( '#state-panel' ) . getBoundingClientRect ( ) ;
145
- if ( consider_state_panel || panel_active . height < 25 ) {
143
+ if ( consider_state_panel || panel_active . height < 25 ) {
146
144
document . state_panel_height = panel_active . height ;
147
145
}
148
146
// 25 是chatbot的label高度, 16 是右侧的gap
149
- var panel_height_target = panel1 . height + panel2 . height + panel3 . height + 0 + 0 - 25 + 16 * 2 ;
147
+ var panel_height_target = panel1 . height + panel2 . height + panel3 . height + 0 + 0 - 25 + 16 * 2 ;
150
148
// 禁止动态的state-panel高度影响
151
- panel_height_target = panel_height_target + ( document . state_panel_height - panel_active . height )
149
+ panel_height_target = panel_height_target + ( document . state_panel_height - panel_active . height )
152
150
var panel_height_target = parseInt ( panel_height_target ) ;
153
151
var chatbot_height = chatbot . style . height ;
154
152
var chatbot_height = parseInt ( chatbot_height ) ;
@@ -173,7 +171,7 @@ function add_func_paste(input) {
173
171
}
174
172
if ( paste_files . length > 0 ) {
175
173
// 按照文件列表执行批量上传逻辑
176
- await paste_upload_files ( paste_files ) ;
174
+ await upload_files ( paste_files ) ;
177
175
paste_files = [ ]
178
176
179
177
}
@@ -182,8 +180,42 @@ function add_func_paste(input) {
182
180
}
183
181
}
184
182
183
+ function add_func_drag ( elem ) {
184
+ if ( elem ) {
185
+ const dragEvents = [ "dragover" , "dragenter" ] ;
186
+ const leaveEvents = [ "dragleave" , "dragend" , "drop" ] ;
187
+
188
+ const onDrag = function ( e ) {
189
+ e . preventDefault ( ) ;
190
+ e . stopPropagation ( ) ;
191
+ if ( elem_upload_float . querySelector ( "input[type=file]" ) ) {
192
+ toast_push ( '释放以上传文件' , 50 )
193
+ } else {
194
+ toast_push ( '⚠️请先删除上传区中的历史文件,再尝试上传。' , 50 )
195
+ }
196
+ } ;
197
+
198
+ const onLeave = function ( e ) {
199
+ e . preventDefault ( ) ;
200
+ e . stopPropagation ( ) ;
201
+ } ;
202
+
203
+ dragEvents . forEach ( event => {
204
+ elem . addEventListener ( event , onDrag ) ;
205
+ } ) ;
206
+
207
+ leaveEvents . forEach ( event => {
208
+ elem . addEventListener ( event , onLeave ) ;
209
+ } ) ;
185
210
186
- async function paste_upload_files ( files ) {
211
+ elem . addEventListener ( "drop" , async function ( e ) {
212
+ const files = e . dataTransfer . files ;
213
+ await upload_files ( files ) ;
214
+ } ) ;
215
+ }
216
+ }
217
+
218
+ async function upload_files ( files ) {
187
219
const uploadInputElement = elem_upload_float . querySelector ( "input[type=file]" ) ;
188
220
let totalSizeMb = 0
189
221
if ( files && files . length > 0 ) {
@@ -195,19 +227,20 @@ async function paste_upload_files(files) {
195
227
}
196
228
// 检查文件总大小是否超过20MB
197
229
if ( totalSizeMb > 20 ) {
198
- toast_push ( '⚠️文件夹大于20MB 🚀上传文件中' , 2000 )
230
+ toast_push ( '⚠️文件夹大于 20MB 🚀上传文件中' , 3000 )
199
231
// return; // 如果超过了指定大小, 可以不进行后续上传操作
200
232
}
201
- // 监听change事件, 原生Gradio可以实现
233
+ // 监听change事件, 原生Gradio可以实现
202
234
// uploadInputElement.addEventListener('change', function(){replace_input_string()});
203
235
let event = new Event ( "change" ) ;
204
- Object . defineProperty ( event , "target" , { value : uploadInputElement , enumerable : true } ) ;
205
- Object . defineProperty ( event , "currentTarget" , { value : uploadInputElement , enumerable : true } ) ;
206
- Object . defineProperty ( uploadInputElement , "files" , { value : files , enumerable : true } ) ;
236
+ Object . defineProperty ( event , "target" , { value : uploadInputElement , enumerable : true } ) ;
237
+ Object . defineProperty ( event , "currentTarget" , { value : uploadInputElement , enumerable : true } ) ;
238
+ Object . defineProperty ( uploadInputElement , "files" , { value : files , enumerable : true } ) ;
207
239
uploadInputElement . dispatchEvent ( event ) ;
240
+
208
241
// toast_push('🎉上传文件成功', 2000)
209
242
} else {
210
- toast_push ( '⚠️请先删除上传区中的历史文件,再尝试粘贴 。' , 2000 )
243
+ toast_push ( '⚠️请先删除上传区中的历史文件,再尝试上传 。' , 3000 )
211
244
}
212
245
}
213
246
}
@@ -231,23 +264,85 @@ var elem_upload = null;
231
264
var elem_upload_float = null ;
232
265
var elem_input_main = null ;
233
266
var elem_input_float = null ;
267
+ var gptChatbot = null ;
234
268
235
269
270
+ function begin_loading_status ( ) {
271
+ // Create the loader div and add styling
272
+ var loader = document . createElement ( 'div' ) ;
273
+ loader . id = 'Js_File_Loading' ;
274
+ loader . style . position = "absolute" ;
275
+ loader . style . top = "50%" ;
276
+ loader . style . left = "50%" ;
277
+ loader . style . width = "60px" ;
278
+ loader . style . height = "60px" ;
279
+ loader . style . border = "16px solid #f3f3f3" ;
280
+ loader . style . borderTop = "16px solid #3498db" ;
281
+ loader . style . borderRadius = "50%" ;
282
+ loader . style . animation = "spin 2s linear infinite" ;
283
+ loader . style . transform = "translate(-50%, -50%)" ;
284
+ document . body . appendChild ( loader ) ; // Add the loader to the body
285
+ // Set the CSS animation keyframes
286
+ var styleSheet = document . createElement ( 'style' ) ;
287
+ // styleSheet.type = 'text/css';
288
+ styleSheet . id = 'Js_File_Loading_Style'
289
+ styleSheet . innerText = `
290
+ @keyframes spin {
291
+ 0% { transform: rotate(0deg); }
292
+ 100% { transform: rotate(360deg); }
293
+ }` ;
294
+ document . head . appendChild ( styleSheet ) ;
295
+ }
296
+ function cancel_loading_status ( ) {
297
+ var loadingElement = document . getElementById ( 'Js_File_Loading' ) ;
298
+ if ( loadingElement ) {
299
+ document . body . removeChild ( loadingElement ) ; // remove the loader from the body
300
+ }
301
+ var loadingStyle = document . getElementById ( 'Js_File_Loading_Style' ) ;
302
+ if ( loadingStyle ) {
303
+ document . head . removeChild ( loadingStyle ) ;
304
+ }
305
+ let clearButton = document . querySelectorAll ( 'div[id*="elem_upload"] button[aria-label="Clear"]' ) ;
306
+ for ( let button of clearButton ) {
307
+ button . addEventListener ( 'click' , function ( ) {
308
+ setTimeout ( function ( ) {
309
+ register_upload_event ( ) ;
310
+ } , 50 ) ;
311
+ } ) ;
312
+ }
313
+ }
314
+ function register_upload_event ( ) {
315
+ elem_upload_float = document . getElementById ( 'elem_upload_float' )
316
+ const upload_component = elem_upload_float . querySelector ( "input[type=file]" ) ;
317
+ if ( upload_component ) {
318
+ upload_component . addEventListener ( 'change' , function ( event ) {
319
+ toast_push ( '正在上传中,请稍等。' , 2000 ) ;
320
+ begin_loading_status ( ) ;
321
+ } ) ;
322
+ }
323
+ }
236
324
function monitoring_input_box ( ) {
325
+ register_upload_event ( ) ;
326
+
237
327
elem_upload = document . getElementById ( 'elem_upload' )
238
328
elem_upload_float = document . getElementById ( 'elem_upload_float' )
239
329
elem_input_main = document . getElementById ( 'user_input_main' )
240
330
elem_input_float = document . getElementById ( 'user_input_float' )
331
+
241
332
if ( elem_input_main ) {
242
333
if ( elem_input_main . querySelector ( "textarea" ) ) {
243
334
add_func_paste ( elem_input_main . querySelector ( "textarea" ) )
244
335
}
245
336
}
246
337
if ( elem_input_float ) {
247
- if ( elem_input_float . querySelector ( "textarea" ) ) {
338
+ if ( elem_input_float . querySelector ( "textarea" ) ) {
248
339
add_func_paste ( elem_input_float . querySelector ( "textarea" ) )
249
340
}
250
341
}
342
+ gptChatbot = document . getElementById ( 'gpt-chatbot' )
343
+ if ( gptChatbot ) {
344
+ add_func_drag ( gptChatbot )
345
+ }
251
346
}
252
347
253
348
@@ -259,28 +354,28 @@ window.addEventListener("DOMContentLoaded", function () {
259
354
260
355
function audio_fn_init ( ) {
261
356
let audio_component = document . getElementById ( 'elem_audio' ) ;
262
- if ( audio_component ) {
357
+ if ( audio_component ) {
263
358
let buttonElement = audio_component . querySelector ( 'button' ) ;
264
359
let specificElement = audio_component . querySelector ( '.hide.sr-only' ) ;
265
360
specificElement . remove ( ) ;
266
361
267
362
buttonElement . childNodes [ 1 ] . nodeValue = '启动麦克风' ;
268
- buttonElement . addEventListener ( 'click' , function ( event ) {
363
+ buttonElement . addEventListener ( 'click' , function ( event ) {
269
364
event . stopPropagation ( ) ;
270
365
toast_push ( '您启动了麦克风!下一步请点击“实时语音对话”启动语音对话。' ) ;
271
366
} ) ;
272
367
273
368
// 查找语音插件按钮
274
369
let buttons = document . querySelectorAll ( 'button' ) ;
275
370
let audio_button = null ;
276
- for ( let button of buttons ) {
277
- if ( button . textContent . includes ( '语音' ) ) {
371
+ for ( let button of buttons ) {
372
+ if ( button . textContent . includes ( '语音' ) ) {
278
373
audio_button = button ;
279
374
break ;
280
375
}
281
376
}
282
- if ( audio_button ) {
283
- audio_button . addEventListener ( 'click' , function ( ) {
377
+ if ( audio_button ) {
378
+ audio_button . addEventListener ( 'click' , function ( ) {
284
379
toast_push ( '您点击了“实时语音对话”启动语音对话。' ) ;
285
380
} ) ;
286
381
let parent_element = audio_component . parentElement ; // 将buttonElement移动到audio_button的内部
@@ -300,5 +395,5 @@ function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") {
300
395
chatbotContentChanged ( 1 ) ;
301
396
} ) ;
302
397
chatbotObserver . observe ( chatbotIndicator , { attributes : true , childList : true , subtree : true } ) ;
303
- if ( LAYOUT === "LEFT-RIGHT" ) { chatbotAutoHeight ( ) ; }
398
+ if ( LAYOUT === "LEFT-RIGHT" ) { chatbotAutoHeight ( ) ; }
304
399
}
0 commit comments