@gradio/core 0.17.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/dist/src/Blocks.svelte +74 -4
- package/dist/src/api_docs/ApiDocs.svelte +17 -17
- package/dist/src/api_docs/Settings.svelte +74 -1
- package/dist/src/api_docs/Settings.svelte.d.ts +3 -0
- package/dist/src/api_docs/img/record-stop.svg +1 -0
- package/dist/src/api_docs/img/record.svg +1 -0
- package/dist/src/init.js +7 -3
- package/dist/src/lang/en.json +4 -0
- package/dist/src/screen_recorder.d.ts +16 -0
- package/dist/src/screen_recorder.js +255 -0
- package/package.json +46 -46
- package/src/Blocks.svelte +85 -6
- package/src/api_docs/ApiDocs.svelte +18 -17
- package/src/api_docs/Settings.svelte +77 -1
- package/src/api_docs/img/record-stop.svg +1 -0
- package/src/api_docs/img/record.svg +1 -0
- package/src/init.ts +7 -6
- package/src/lang/en.json +4 -0
- package/src/screen_recorder.ts +361 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
let isRecording = false;
|
|
2
|
+
let mediaRecorder = null;
|
|
3
|
+
let recordedChunks = [];
|
|
4
|
+
let recordingStartTime = 0;
|
|
5
|
+
let animationFrameId = null;
|
|
6
|
+
let removeSegment = {};
|
|
7
|
+
let root;
|
|
8
|
+
let add_message_callback;
|
|
9
|
+
let onRecordingStateChange = null;
|
|
10
|
+
let zoomEffects = [];
|
|
11
|
+
export function initialize(rootPath, add_new_message, recordingStateCallback) {
|
|
12
|
+
root = rootPath;
|
|
13
|
+
add_message_callback = add_new_message;
|
|
14
|
+
if (recordingStateCallback) {
|
|
15
|
+
onRecordingStateChange = recordingStateCallback;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function startRecording() {
|
|
19
|
+
if (isRecording) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const originalTitle = document.title;
|
|
24
|
+
document.title = "[Sharing] Gradio Tab";
|
|
25
|
+
const stream = await navigator.mediaDevices.getDisplayMedia({
|
|
26
|
+
video: {
|
|
27
|
+
width: { ideal: 1920 },
|
|
28
|
+
height: { ideal: 1080 },
|
|
29
|
+
frameRate: { ideal: 30 }
|
|
30
|
+
},
|
|
31
|
+
audio: true,
|
|
32
|
+
selfBrowserSurface: "include"
|
|
33
|
+
});
|
|
34
|
+
document.title = originalTitle;
|
|
35
|
+
const options = {
|
|
36
|
+
videoBitsPerSecond: 5000000
|
|
37
|
+
};
|
|
38
|
+
mediaRecorder = new MediaRecorder(stream, options);
|
|
39
|
+
recordedChunks = [];
|
|
40
|
+
removeSegment = {};
|
|
41
|
+
mediaRecorder.ondataavailable = handleDataAvailable;
|
|
42
|
+
mediaRecorder.onstop = handleStop;
|
|
43
|
+
mediaRecorder.start(1000);
|
|
44
|
+
isRecording = true;
|
|
45
|
+
if (onRecordingStateChange) {
|
|
46
|
+
onRecordingStateChange(true);
|
|
47
|
+
}
|
|
48
|
+
recordingStartTime = Date.now();
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
add_message_callback("Recording Error", "Failed to start recording: " + error.message, "error");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function stopRecording() {
|
|
55
|
+
if (!isRecording || !mediaRecorder) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
mediaRecorder.stop();
|
|
59
|
+
isRecording = false;
|
|
60
|
+
if (onRecordingStateChange) {
|
|
61
|
+
onRecordingStateChange(false);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function isCurrentlyRecording() {
|
|
65
|
+
return isRecording;
|
|
66
|
+
}
|
|
67
|
+
export function markRemoveSegmentStart() {
|
|
68
|
+
if (!isRecording) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const currentTime = (Date.now() - recordingStartTime) / 1000;
|
|
72
|
+
removeSegment.start = currentTime;
|
|
73
|
+
}
|
|
74
|
+
export function markRemoveSegmentEnd() {
|
|
75
|
+
if (!isRecording || removeSegment.start === undefined) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const currentTime = (Date.now() - recordingStartTime) / 1000;
|
|
79
|
+
removeSegment.end = currentTime;
|
|
80
|
+
}
|
|
81
|
+
export function clearRemoveSegment() {
|
|
82
|
+
removeSegment = {};
|
|
83
|
+
}
|
|
84
|
+
export function addZoomEffect(is_input, params) {
|
|
85
|
+
if (!isRecording) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const FPS = 30;
|
|
89
|
+
const currentTime = (Date.now() - recordingStartTime) / 1000;
|
|
90
|
+
const currentFrame = is_input
|
|
91
|
+
? Math.floor((currentTime - 2) * FPS)
|
|
92
|
+
: Math.floor(currentTime * FPS);
|
|
93
|
+
if (params.boundingBox &&
|
|
94
|
+
params.boundingBox.topLeft &&
|
|
95
|
+
params.boundingBox.bottomRight &&
|
|
96
|
+
params.boundingBox.topLeft.length === 2 &&
|
|
97
|
+
params.boundingBox.bottomRight.length === 2) {
|
|
98
|
+
const newEffectDuration = params.duration || 2.0;
|
|
99
|
+
const newEffectEndFrame = currentFrame + Math.floor(newEffectDuration * FPS);
|
|
100
|
+
const hasOverlap = zoomEffects.some((existingEffect) => {
|
|
101
|
+
const existingEffectEndFrame = existingEffect.start_frame +
|
|
102
|
+
Math.floor((existingEffect.duration || 2.0) * FPS);
|
|
103
|
+
return ((currentFrame >= existingEffect.start_frame &&
|
|
104
|
+
currentFrame <= existingEffectEndFrame) ||
|
|
105
|
+
(newEffectEndFrame >= existingEffect.start_frame &&
|
|
106
|
+
newEffectEndFrame <= existingEffectEndFrame) ||
|
|
107
|
+
(currentFrame <= existingEffect.start_frame &&
|
|
108
|
+
newEffectEndFrame >= existingEffectEndFrame));
|
|
109
|
+
});
|
|
110
|
+
if (!hasOverlap) {
|
|
111
|
+
zoomEffects.push({
|
|
112
|
+
boundingBox: params.boundingBox,
|
|
113
|
+
start_frame: currentFrame,
|
|
114
|
+
duration: newEffectDuration
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function zoom(is_input, elements, duration = 2.0) {
|
|
120
|
+
if (!isRecording) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
if (!elements || elements.length === 0) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
let minLeft = Infinity;
|
|
129
|
+
let minTop = Infinity;
|
|
130
|
+
let maxRight = 0;
|
|
131
|
+
let maxBottom = 0;
|
|
132
|
+
let foundElements = false;
|
|
133
|
+
for (const elementId of elements) {
|
|
134
|
+
const selector = `#component-${elementId}`;
|
|
135
|
+
const element = document.querySelector(selector);
|
|
136
|
+
if (element) {
|
|
137
|
+
foundElements = true;
|
|
138
|
+
const rect = element.getBoundingClientRect();
|
|
139
|
+
minLeft = Math.min(minLeft, rect.left);
|
|
140
|
+
minTop = Math.min(minTop, rect.top);
|
|
141
|
+
maxRight = Math.max(maxRight, rect.right);
|
|
142
|
+
maxBottom = Math.max(maxBottom, rect.bottom);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (!foundElements) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const viewportWidth = window.innerWidth;
|
|
149
|
+
const viewportHeight = window.innerHeight;
|
|
150
|
+
const boxWidth = Math.min(maxRight, viewportWidth) - Math.max(0, minLeft);
|
|
151
|
+
const boxHeight = Math.min(maxBottom, viewportHeight) - Math.max(0, minTop);
|
|
152
|
+
const widthPercentage = boxWidth / viewportWidth;
|
|
153
|
+
const heightPercentage = boxHeight / viewportHeight;
|
|
154
|
+
if (widthPercentage >= 0.8 || heightPercentage >= 0.8) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
158
|
+
let topLeft = [
|
|
159
|
+
Math.max(0, minLeft) / viewportWidth,
|
|
160
|
+
Math.max(0, minTop) / viewportHeight
|
|
161
|
+
];
|
|
162
|
+
let bottomRight = [
|
|
163
|
+
Math.min(maxRight, viewportWidth) / viewportWidth,
|
|
164
|
+
Math.min(maxBottom, viewportHeight) / viewportHeight
|
|
165
|
+
];
|
|
166
|
+
if (isSafari) {
|
|
167
|
+
topLeft[0] = Math.max(0, topLeft[0] * 0.9);
|
|
168
|
+
bottomRight[0] = Math.min(1, bottomRight[0] * 0.9);
|
|
169
|
+
const width = bottomRight[0] - topLeft[0];
|
|
170
|
+
const center = (topLeft[0] + bottomRight[0]) / 2;
|
|
171
|
+
const newCenter = center * 0.9;
|
|
172
|
+
topLeft[0] = Math.max(0, newCenter - width / 2);
|
|
173
|
+
bottomRight[0] = Math.min(1, newCenter + width / 2);
|
|
174
|
+
}
|
|
175
|
+
topLeft[0] = Math.max(0, topLeft[0]);
|
|
176
|
+
topLeft[1] = Math.max(0, topLeft[1]);
|
|
177
|
+
bottomRight[0] = Math.min(1, bottomRight[0]);
|
|
178
|
+
bottomRight[1] = Math.min(1, bottomRight[1]);
|
|
179
|
+
addZoomEffect(is_input, {
|
|
180
|
+
boundingBox: {
|
|
181
|
+
topLeft,
|
|
182
|
+
bottomRight
|
|
183
|
+
},
|
|
184
|
+
duration: duration
|
|
185
|
+
});
|
|
186
|
+
}, 300);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
// pass
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function handleDataAvailable(event) {
|
|
193
|
+
if (event.data.size > 0) {
|
|
194
|
+
recordedChunks.push(event.data);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function handleStop() {
|
|
198
|
+
isRecording = false;
|
|
199
|
+
if (onRecordingStateChange) {
|
|
200
|
+
onRecordingStateChange(false);
|
|
201
|
+
}
|
|
202
|
+
const blob = new Blob(recordedChunks, {
|
|
203
|
+
type: "video/mp4"
|
|
204
|
+
});
|
|
205
|
+
handleRecordingComplete(blob);
|
|
206
|
+
const screenStream = mediaRecorder?.stream?.getTracks() || [];
|
|
207
|
+
screenStream.forEach((track) => track.stop());
|
|
208
|
+
if (animationFrameId !== null) {
|
|
209
|
+
cancelAnimationFrame(animationFrameId);
|
|
210
|
+
animationFrameId = null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function handleRecordingComplete(recordedBlob) {
|
|
214
|
+
try {
|
|
215
|
+
add_message_callback("Processing video", "This may take a few seconds...", "info");
|
|
216
|
+
const formData = new FormData();
|
|
217
|
+
formData.append("video", recordedBlob, "recording.mp4");
|
|
218
|
+
if (removeSegment.start !== undefined && removeSegment.end !== undefined) {
|
|
219
|
+
formData.append("remove_segment_start", removeSegment.start.toString());
|
|
220
|
+
formData.append("remove_segment_end", removeSegment.end.toString());
|
|
221
|
+
}
|
|
222
|
+
if (zoomEffects.length > 0) {
|
|
223
|
+
formData.append("zoom_effects", JSON.stringify(zoomEffects));
|
|
224
|
+
}
|
|
225
|
+
const response = await fetch(root + "/gradio_api/process_recording", {
|
|
226
|
+
method: "POST",
|
|
227
|
+
body: formData
|
|
228
|
+
});
|
|
229
|
+
if (!response.ok) {
|
|
230
|
+
throw new Error(`Server returned ${response.status}: ${response.statusText}`);
|
|
231
|
+
}
|
|
232
|
+
const processedBlob = await response.blob();
|
|
233
|
+
const defaultFilename = `gradio-screen-recording-${new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "")}.mp4`;
|
|
234
|
+
saveWithDownloadAttribute(processedBlob, defaultFilename);
|
|
235
|
+
zoomEffects = [];
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
add_message_callback("Processing Error", "Failed to process recording. Saving original version.", "warning");
|
|
239
|
+
const defaultFilename = `gradio-screen-recording-${new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "")}.mp4`;
|
|
240
|
+
saveWithDownloadAttribute(recordedBlob, defaultFilename);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function saveWithDownloadAttribute(blob, suggestedName) {
|
|
244
|
+
const url = URL.createObjectURL(blob);
|
|
245
|
+
const a = document.createElement("a");
|
|
246
|
+
a.style.display = "none";
|
|
247
|
+
a.href = url;
|
|
248
|
+
a.download = suggestedName;
|
|
249
|
+
document.body.appendChild(a);
|
|
250
|
+
a.click();
|
|
251
|
+
setTimeout(() => {
|
|
252
|
+
document.body.removeChild(a);
|
|
253
|
+
URL.revokeObjectURL(url);
|
|
254
|
+
}, 100);
|
|
255
|
+
}
|
package/package.json
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"devDependencies": {
|
|
6
|
-
"@gradio/accordion": "^0.5.
|
|
7
|
-
"@gradio/annotatedimage": "^0.9.
|
|
6
|
+
"@gradio/accordion": "^0.5.16",
|
|
7
|
+
"@gradio/annotatedimage": "^0.9.20",
|
|
8
8
|
"@gradio/atoms": "^0.16.1",
|
|
9
|
-
"@gradio/audio": "^0.17.14",
|
|
10
9
|
"@gradio/box": "^0.2.19",
|
|
11
|
-
"@gradio/
|
|
12
|
-
"@gradio/button": "^0.5.
|
|
13
|
-
"@gradio/
|
|
14
|
-
"@gradio/
|
|
15
|
-
"@gradio/
|
|
16
|
-
"@gradio/code": "^0.14.
|
|
17
|
-
"@gradio/
|
|
10
|
+
"@gradio/audio": "^0.17.15",
|
|
11
|
+
"@gradio/button": "^0.5.1",
|
|
12
|
+
"@gradio/chatbot": "^0.26.9",
|
|
13
|
+
"@gradio/checkbox": "^0.4.22",
|
|
14
|
+
"@gradio/checkboxgroup": "^0.6.22",
|
|
15
|
+
"@gradio/code": "^0.14.5",
|
|
16
|
+
"@gradio/client": "^1.15.1",
|
|
17
|
+
"@gradio/colorpicker": "^0.4.22",
|
|
18
18
|
"@gradio/column": "^0.2.0",
|
|
19
|
-
"@gradio/
|
|
20
|
-
"@gradio/
|
|
21
|
-
"@gradio/
|
|
22
|
-
"@gradio/downloadbutton": "^0.4.
|
|
23
|
-
"@gradio/
|
|
24
|
-
"@gradio/file": "^0.12.
|
|
19
|
+
"@gradio/datetime": "^0.3.14",
|
|
20
|
+
"@gradio/dataframe": "^0.17.13",
|
|
21
|
+
"@gradio/dataset": "^0.4.20",
|
|
22
|
+
"@gradio/downloadbutton": "^0.4.1",
|
|
23
|
+
"@gradio/fallback": "^0.4.22",
|
|
24
|
+
"@gradio/file": "^0.12.19",
|
|
25
|
+
"@gradio/dropdown": "^0.9.22",
|
|
26
|
+
"@gradio/fileexplorer": "^0.5.30",
|
|
25
27
|
"@gradio/form": "^0.2.19",
|
|
26
|
-
"@gradio/fallback": "^0.4.21",
|
|
27
|
-
"@gradio/fileexplorer": "^0.5.29",
|
|
28
|
-
"@gradio/highlightedtext": "^0.9.4",
|
|
29
|
-
"@gradio/gallery": "^0.15.19",
|
|
30
|
-
"@gradio/html": "^0.6.13",
|
|
31
28
|
"@gradio/group": "^0.2.0",
|
|
32
29
|
"@gradio/icons": "^0.12.0",
|
|
33
|
-
"@gradio/
|
|
34
|
-
"@gradio/
|
|
35
|
-
"@gradio/
|
|
36
|
-
"@gradio/
|
|
37
|
-
"@gradio/
|
|
30
|
+
"@gradio/gallery": "^0.15.20",
|
|
31
|
+
"@gradio/html": "^0.6.14",
|
|
32
|
+
"@gradio/image": "^0.22.7",
|
|
33
|
+
"@gradio/imageslider": "^0.2.3",
|
|
34
|
+
"@gradio/imageeditor": "^0.15.1",
|
|
35
|
+
"@gradio/highlightedtext": "^0.9.5",
|
|
36
|
+
"@gradio/json": "^0.5.24",
|
|
37
|
+
"@gradio/label": "^0.5.14",
|
|
38
38
|
"@gradio/browserstate": "^0.3.2",
|
|
39
|
-
"@gradio/markdown": "^0.13.
|
|
40
|
-
"@gradio/multimodaltextbox": "^0.10.
|
|
41
|
-
"@gradio/
|
|
42
|
-
"@gradio/
|
|
43
|
-
"@gradio/
|
|
44
|
-
"@gradio/
|
|
45
|
-
"@gradio/
|
|
46
|
-
"@gradio/radio": "^0.7.
|
|
39
|
+
"@gradio/markdown": "^0.13.14",
|
|
40
|
+
"@gradio/multimodaltextbox": "^0.10.7",
|
|
41
|
+
"@gradio/model3d": "^0.14.15",
|
|
42
|
+
"@gradio/nativeplot": "^0.5.17",
|
|
43
|
+
"@gradio/paramviewer": "^0.7.10",
|
|
44
|
+
"@gradio/plot": "^0.9.17",
|
|
45
|
+
"@gradio/number": "^0.5.22",
|
|
46
|
+
"@gradio/radio": "^0.7.5",
|
|
47
|
+
"@gradio/sidebar": "^0.1.14",
|
|
47
48
|
"@gradio/row": "^0.2.1",
|
|
48
|
-
"@gradio/
|
|
49
|
-
"@gradio/simpledropdown": "^0.3.
|
|
50
|
-
"@gradio/
|
|
51
|
-
"@gradio/
|
|
52
|
-
"@gradio/
|
|
53
|
-
"@gradio/
|
|
54
|
-
"@gradio/statustracker": "^0.10.11",
|
|
49
|
+
"@gradio/simpleimage": "^0.8.30",
|
|
50
|
+
"@gradio/simpledropdown": "^0.3.22",
|
|
51
|
+
"@gradio/simpletextbox": "^0.3.22",
|
|
52
|
+
"@gradio/sketchbox": "^0.6.9",
|
|
53
|
+
"@gradio/slider": "^0.6.11",
|
|
54
|
+
"@gradio/statustracker": "^0.10.12",
|
|
55
55
|
"@gradio/state": "^0.1.2",
|
|
56
56
|
"@gradio/tabitem": "^0.4.4",
|
|
57
57
|
"@gradio/tabs": "^0.4.4",
|
|
58
|
-
"@gradio/textbox": "^0.10.11",
|
|
59
58
|
"@gradio/theme": "^0.4.0",
|
|
59
|
+
"@gradio/upload": "^0.16.6",
|
|
60
|
+
"@gradio/textbox": "^0.10.12",
|
|
60
61
|
"@gradio/timer": "^0.4.5",
|
|
61
|
-
"@gradio/upload": "^0.16.5",
|
|
62
|
-
"@gradio/uploadbutton": "^0.9.0",
|
|
63
62
|
"@gradio/utils": "^0.10.2",
|
|
63
|
+
"@gradio/video": "^0.14.15",
|
|
64
64
|
"@gradio/wasm": "^0.18.1",
|
|
65
|
-
"@gradio/
|
|
65
|
+
"@gradio/uploadbutton": "^0.9.1"
|
|
66
66
|
},
|
|
67
67
|
"msw": {
|
|
68
68
|
"workerDirectory": "public"
|
package/src/Blocks.svelte
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { tick, onMount } from "svelte";
|
|
3
3
|
import { _ } from "svelte-i18n";
|
|
4
4
|
import { Client } from "@gradio/client";
|
|
5
|
+
import { writable } from "svelte/store";
|
|
5
6
|
|
|
6
7
|
import type { LoadingStatus, LoadingStatusCollection } from "./stores";
|
|
7
8
|
|
|
@@ -19,12 +20,14 @@
|
|
|
19
20
|
import logo from "./images/logo.svg";
|
|
20
21
|
import api_logo from "./api_docs/img/api-logo.svg";
|
|
21
22
|
import settings_logo from "./api_docs/img/settings-logo.svg";
|
|
23
|
+
import record_stop from "./api_docs/img/record-stop.svg";
|
|
22
24
|
import { create_components, AsyncFunction } from "./init";
|
|
23
25
|
import type {
|
|
24
26
|
LogMessage,
|
|
25
27
|
RenderMessage,
|
|
26
28
|
StatusMessage
|
|
27
29
|
} from "@gradio/client";
|
|
30
|
+
import * as screen_recorder from "./screen_recorder";
|
|
28
31
|
|
|
29
32
|
export let root: string;
|
|
30
33
|
export let components: ComponentMeta[];
|
|
@@ -50,8 +53,6 @@
|
|
|
50
53
|
export let initial_layout: ComponentMeta | undefined = undefined;
|
|
51
54
|
export let css: string | null | undefined = null;
|
|
52
55
|
|
|
53
|
-
setupi18n(app.config?.i18n_translations ?? undefined);
|
|
54
|
-
|
|
55
56
|
let {
|
|
56
57
|
layout: _layout,
|
|
57
58
|
targets,
|
|
@@ -97,6 +98,8 @@
|
|
|
97
98
|
let settings_visible = search_params.get("view") === "settings";
|
|
98
99
|
let api_recorder_visible =
|
|
99
100
|
search_params.get("view") === "api-recorder" && show_api;
|
|
101
|
+
let allow_zoom = true;
|
|
102
|
+
let allow_video_trim = true;
|
|
100
103
|
|
|
101
104
|
function set_api_docs_visible(visible: boolean): void {
|
|
102
105
|
api_recorder_visible = false;
|
|
@@ -126,11 +129,28 @@
|
|
|
126
129
|
export let render_complete = false;
|
|
127
130
|
async function handle_update(data: any, fn_index: number): Promise<void> {
|
|
128
131
|
const dep = dependencies.find((dep) => dep.id === fn_index);
|
|
132
|
+
const input_type = components.find(
|
|
133
|
+
(comp) => comp.id === dep?.inputs[0]
|
|
134
|
+
)?.type;
|
|
135
|
+
if (allow_zoom && dep && input_type !== "dataset") {
|
|
136
|
+
if (dep && dep.inputs && dep.inputs.length > 0 && $is_screen_recording) {
|
|
137
|
+
screen_recorder.zoom(true, dep.inputs, 1.0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (
|
|
141
|
+
dep &&
|
|
142
|
+
dep.outputs &&
|
|
143
|
+
dep.outputs.length > 0 &&
|
|
144
|
+
$is_screen_recording
|
|
145
|
+
) {
|
|
146
|
+
screen_recorder.zoom(false, dep.outputs, 2.0);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
129
150
|
if (!dep) {
|
|
130
151
|
return;
|
|
131
152
|
}
|
|
132
153
|
const outputs = dep.outputs;
|
|
133
|
-
|
|
134
154
|
const meta_updates = data?.map((value: any, i: number) => {
|
|
135
155
|
return {
|
|
136
156
|
id: outputs[i],
|
|
@@ -372,6 +392,9 @@
|
|
|
372
392
|
payload: Payload,
|
|
373
393
|
streaming = false
|
|
374
394
|
): Promise<void> {
|
|
395
|
+
if (allow_video_trim) {
|
|
396
|
+
screen_recorder.markRemoveSegmentStart();
|
|
397
|
+
}
|
|
375
398
|
if (api_recorder_visible) {
|
|
376
399
|
api_calls = [...api_calls, JSON.parse(JSON.stringify(payload))];
|
|
377
400
|
}
|
|
@@ -601,6 +624,9 @@
|
|
|
601
624
|
});
|
|
602
625
|
}
|
|
603
626
|
}
|
|
627
|
+
if (allow_video_trim) {
|
|
628
|
+
screen_recorder.markRemoveSegmentEnd();
|
|
629
|
+
}
|
|
604
630
|
}
|
|
605
631
|
}
|
|
606
632
|
/* eslint-enable complexity */
|
|
@@ -773,6 +799,8 @@
|
|
|
773
799
|
return "detail" in event;
|
|
774
800
|
}
|
|
775
801
|
|
|
802
|
+
let is_screen_recording = writable(false);
|
|
803
|
+
|
|
776
804
|
onMount(() => {
|
|
777
805
|
document.addEventListener("visibilitychange", function () {
|
|
778
806
|
if (document.visibilityState === "hidden") {
|
|
@@ -784,6 +812,29 @@
|
|
|
784
812
|
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
785
813
|
navigator.userAgent
|
|
786
814
|
);
|
|
815
|
+
|
|
816
|
+
screen_recorder.initialize(
|
|
817
|
+
root,
|
|
818
|
+
(title, message, type) => {
|
|
819
|
+
add_new_message(title, message, type);
|
|
820
|
+
},
|
|
821
|
+
(isRecording) => {
|
|
822
|
+
$is_screen_recording = isRecording;
|
|
823
|
+
}
|
|
824
|
+
);
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
function screen_recording(): void {
|
|
828
|
+
if ($is_screen_recording) {
|
|
829
|
+
screen_recorder.stopRecording();
|
|
830
|
+
} else {
|
|
831
|
+
screen_recorder.startRecording();
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
let i18n_ready = false;
|
|
836
|
+
setupi18n(app.config?.i18n_translations ?? undefined).then(() => {
|
|
837
|
+
i18n_ready = true;
|
|
787
838
|
});
|
|
788
839
|
</script>
|
|
789
840
|
|
|
@@ -798,7 +849,7 @@
|
|
|
798
849
|
|
|
799
850
|
<div class="wrap" style:min-height={app_mode ? "100%" : "auto"}>
|
|
800
851
|
<div class="contain" style:flex-grow={app_mode ? "1" : "auto"}>
|
|
801
|
-
{#if $_layout && app.config}
|
|
852
|
+
{#if $_layout && app.config && i18n_ready}
|
|
802
853
|
<MountComponents
|
|
803
854
|
rootNode={$_layout}
|
|
804
855
|
{root}
|
|
@@ -840,6 +891,17 @@
|
|
|
840
891
|
{$_("common.built_with_gradio")}
|
|
841
892
|
<img src={logo} alt={$_("common.logo")} />
|
|
842
893
|
</a>
|
|
894
|
+
<div class="divider" class:hidden={!$is_screen_recording}>·</div>
|
|
895
|
+
<button
|
|
896
|
+
class:hidden={!$is_screen_recording}
|
|
897
|
+
on:click={() => {
|
|
898
|
+
screen_recording();
|
|
899
|
+
}}
|
|
900
|
+
class="record"
|
|
901
|
+
>
|
|
902
|
+
{$_("common.stop_recording")}
|
|
903
|
+
<img src={record_stop} alt={$_("common.stop_recording")} />
|
|
904
|
+
</button>
|
|
843
905
|
<div class="divider">·</div>
|
|
844
906
|
<button
|
|
845
907
|
on:click={() => {
|
|
@@ -912,9 +974,14 @@
|
|
|
912
974
|
/>
|
|
913
975
|
<div class="api-docs-wrap">
|
|
914
976
|
<Settings
|
|
977
|
+
bind:allow_zoom
|
|
978
|
+
bind:allow_video_trim
|
|
915
979
|
on:close={(event) => {
|
|
916
980
|
set_settings_visible(false);
|
|
917
981
|
}}
|
|
982
|
+
on:start_recording={(event) => {
|
|
983
|
+
screen_recording();
|
|
984
|
+
}}
|
|
918
985
|
pwa_enabled={app.config.pwa}
|
|
919
986
|
{root}
|
|
920
987
|
{space_id}
|
|
@@ -954,7 +1021,8 @@
|
|
|
954
1021
|
}
|
|
955
1022
|
|
|
956
1023
|
.show-api,
|
|
957
|
-
.settings
|
|
1024
|
+
.settings,
|
|
1025
|
+
.record {
|
|
958
1026
|
display: flex;
|
|
959
1027
|
align-items: center;
|
|
960
1028
|
}
|
|
@@ -974,13 +1042,20 @@
|
|
|
974
1042
|
width: var(--size-4);
|
|
975
1043
|
}
|
|
976
1044
|
|
|
1045
|
+
.record img {
|
|
1046
|
+
margin-right: var(--size-1);
|
|
1047
|
+
margin-left: var(--size-1);
|
|
1048
|
+
width: var(--size-3);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
977
1051
|
.built-with {
|
|
978
1052
|
display: flex;
|
|
979
1053
|
align-items: center;
|
|
980
1054
|
}
|
|
981
1055
|
|
|
982
1056
|
.built-with:hover,
|
|
983
|
-
.settings:hover
|
|
1057
|
+
.settings:hover,
|
|
1058
|
+
.record:hover {
|
|
984
1059
|
color: var(--body-text-color);
|
|
985
1060
|
}
|
|
986
1061
|
|
|
@@ -1051,4 +1126,8 @@
|
|
|
1051
1126
|
.show-api:hover {
|
|
1052
1127
|
color: var(--body-text-color);
|
|
1053
1128
|
}
|
|
1129
|
+
|
|
1130
|
+
.hidden {
|
|
1131
|
+
display: none;
|
|
1132
|
+
}
|
|
1054
1133
|
</style>
|
|
@@ -101,6 +101,7 @@
|
|
|
101
101
|
type: string;
|
|
102
102
|
description: string;
|
|
103
103
|
format?: string;
|
|
104
|
+
default?: any;
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
interface Tool {
|
|
@@ -267,24 +268,24 @@
|
|
|
267
268
|
<div class="tool-content">
|
|
268
269
|
{#if Object.keys(tool.parameters).length > 0}
|
|
269
270
|
<div class="tool-parameters">
|
|
270
|
-
{#
|
|
271
|
-
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
</
|
|
283
|
-
|
|
284
|
-
{
|
|
285
|
-
<p>No parameters</p>
|
|
286
|
-
{/if}
|
|
271
|
+
{#each Object.entries(tool.parameters) as [name, param]}
|
|
272
|
+
<div class="parameter">
|
|
273
|
+
<code>{name}</code>
|
|
274
|
+
<span class="parameter-type">
|
|
275
|
+
({param.type}{param.default !== undefined
|
|
276
|
+
? `, default: ${JSON.stringify(param.default)}`
|
|
277
|
+
: ""})
|
|
278
|
+
</span>
|
|
279
|
+
<p class="parameter-description">
|
|
280
|
+
{param.description
|
|
281
|
+
? param.description
|
|
282
|
+
: "⚠︎ No description for this parameter in function docstring"}
|
|
283
|
+
</p>
|
|
284
|
+
</div>
|
|
285
|
+
{/each}
|
|
287
286
|
</div>
|
|
287
|
+
{:else}
|
|
288
|
+
<p>Takes no input parameters</p>
|
|
288
289
|
{/if}
|
|
289
290
|
</div>
|
|
290
291
|
{/if}
|