mirror of
https://github.com/HumanAIGC-Engineering/gradio-webrtc.git
synced 2026-02-05 18:09:23 +08:00
11
frontend/.prettierrc
Normal file
11
frontend/.prettierrc
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.svelte",
|
||||||
|
"options": {
|
||||||
|
"parser": "svelte"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -46,10 +46,7 @@
|
|||||||
msg?.type === "warning" ||
|
msg?.type === "warning" ||
|
||||||
msg?.type === "error"
|
msg?.type === "error"
|
||||||
) {
|
) {
|
||||||
gradio.dispatch(
|
gradio.dispatch(msg?.type === "error" ? "error" : "warning", msg.message);
|
||||||
msg?.type === "error" ? "error" : "warning",
|
|
||||||
msg.message,
|
|
||||||
);
|
|
||||||
} else if (msg?.type === "fetch_output") {
|
} else if (msg?.type === "fetch_output") {
|
||||||
gradio.dispatch("state_change");
|
gradio.dispatch("state_change");
|
||||||
} else if (msg?.type === "send_input") {
|
} else if (msg?.type === "send_input") {
|
||||||
|
|||||||
15
frontend/package-lock.json
generated
15
frontend/package-lock.json
generated
@@ -25,7 +25,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gradio/preview": "0.12.0",
|
"@gradio/preview": "0.12.0",
|
||||||
"prettier": "3.3.3"
|
"prettier": "^3.3.3",
|
||||||
|
"prettier-plugin-svelte": "^3.3.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"svelte": "^4.0.0"
|
"svelte": "^4.0.0"
|
||||||
@@ -4118,6 +4119,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -4128,6 +4130,17 @@
|
|||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier-plugin-svelte": {
|
||||||
|
"version": "3.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz",
|
||||||
|
"integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"prettier": "^3.0.0",
|
||||||
|
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prismjs": {
|
"node_modules/prismjs": {
|
||||||
"version": "1.29.0",
|
"version": "1.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
|
||||||
|
|||||||
@@ -23,7 +23,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gradio/preview": "0.12.0",
|
"@gradio/preview": "0.12.0",
|
||||||
"prettier": "3.3.3"
|
"prettier": "^3.3.3",
|
||||||
|
"prettier-plugin-svelte": "^3.3.3"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
VolumeHigh,
|
VolumeHigh,
|
||||||
Microphone,
|
Microphone,
|
||||||
} from "@gradio/icons";
|
} from "@gradio/icons";
|
||||||
|
import MicrophoneMuted from "./MicrophoneMuted.svelte";
|
||||||
|
|
||||||
import { start, stop } from "./webrtc_utils";
|
import { start, stop } from "./webrtc_utils";
|
||||||
import { get_devices, set_available_devices } from "./stream_utils";
|
import { get_devices, set_available_devices } from "./stream_utils";
|
||||||
@@ -79,6 +80,7 @@
|
|||||||
let selected_device: MediaDeviceInfo | null = null;
|
let selected_device: MediaDeviceInfo | null = null;
|
||||||
let mic_accessed = false;
|
let mic_accessed = false;
|
||||||
let is_muted = false;
|
let is_muted = false;
|
||||||
|
let is_mic_muted = false;
|
||||||
|
|
||||||
const audio_source_callback = () => {
|
const audio_source_callback = () => {
|
||||||
if (mode === "send") return stream;
|
if (mode === "send") return stream;
|
||||||
@@ -257,9 +259,8 @@
|
|||||||
audio: { deviceId: { exact: device_id }, ...track_constraints },
|
audio: { deviceId: { exact: device_id }, ...track_constraints },
|
||||||
});
|
});
|
||||||
selected_device =
|
selected_device =
|
||||||
available_audio_devices.find(
|
available_audio_devices.find((device) => device.deviceId === device_id) ||
|
||||||
(device) => device.deviceId === device_id,
|
null;
|
||||||
) || null;
|
|
||||||
options_open = false;
|
options_open = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -270,6 +271,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleMuteMicrophone(): void {
|
||||||
|
if (stream && stream.getAudioTracks().length > 0) {
|
||||||
|
const audioTrack = stream.getAudioTracks()[0];
|
||||||
|
audioTrack.enabled = !audioTrack.enabled;
|
||||||
|
is_mic_muted = !audioTrack.enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$: if (stopword_recognized) {
|
$: if (stopword_recognized) {
|
||||||
notification_sound.play();
|
notification_sound.play();
|
||||||
}
|
}
|
||||||
@@ -338,10 +347,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div
|
<div class="icon color-primary" title="start recording">
|
||||||
class="icon color-primary"
|
|
||||||
title="start recording"
|
|
||||||
>
|
|
||||||
<Circle />
|
<Circle />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -383,6 +389,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if stream_state === "open" && mode.includes("send")}
|
||||||
|
<button
|
||||||
|
class="mute-button"
|
||||||
|
on:click={toggleMuteMicrophone}
|
||||||
|
aria-label={is_mic_muted ? "unmute mic" : "mute mic"}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="icon"
|
||||||
|
style={`fill: ${icon_button_color}; stroke: ${icon_button_color}; color: ${icon_button_color};`}
|
||||||
|
>
|
||||||
|
{#if is_mic_muted}
|
||||||
|
<MicrophoneMuted />
|
||||||
|
{:else}
|
||||||
|
<Microphone />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
{#if options_open && selected_device}
|
{#if options_open && selected_device}
|
||||||
<select
|
<select
|
||||||
class="select-wrap"
|
class="select-wrap"
|
||||||
@@ -402,8 +426,7 @@
|
|||||||
{#each available_audio_devices as device}
|
{#each available_audio_devices as device}
|
||||||
<option
|
<option
|
||||||
value={device.deviceId}
|
value={device.deviceId}
|
||||||
selected={selected_device.deviceId ===
|
selected={selected_device.deviceId === device.deviceId}
|
||||||
device.deviceId}
|
|
||||||
>
|
>
|
||||||
{device.label}
|
{device.label}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
20
frontend/shared/MicrophoneMuted.svelte
Normal file
20
frontend/shared/MicrophoneMuted.svelte
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="feather feather-mic"
|
||||||
|
><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" /><path
|
||||||
|
d="M19 10v2a7 7 0 0 1-14 0v-2"
|
||||||
|
/><line x1="12" y1="19" x2="12" y2="23" /><line
|
||||||
|
x1="8"
|
||||||
|
y1="23"
|
||||||
|
x2="16"
|
||||||
|
y2="23"
|
||||||
|
/><line x1="1" y1="1" x2="23" y2="23" /></svg
|
||||||
|
>
|
||||||
|
After Width: | Height: | Size: 489 B |
@@ -84,10 +84,7 @@
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
console.info("catching");
|
console.info("catching");
|
||||||
dispatch(
|
dispatch("error", "Too many concurrent users. Come back later!");
|
||||||
"error",
|
|
||||||
"Too many concurrent users. Come back later!",
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
|||||||
@@ -70,10 +70,7 @@
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
dispatch(
|
dispatch("error", "Too many concurrent users. Come back later!");
|
||||||
"error",
|
|
||||||
"Too many concurrent users. Come back later!",
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -37,9 +37,9 @@
|
|||||||
export let pulse_color: string = "var(--color-accent)";
|
export let pulse_color: string = "var(--color-accent)";
|
||||||
export let button_labels: { start: string; stop: string; waiting: string };
|
export let button_labels: { start: string; stop: string; waiting: string };
|
||||||
|
|
||||||
export const modify_stream: (
|
export const modify_stream: (state: "open" | "closed" | "waiting") => void = (
|
||||||
state: "open" | "closed" | "waiting",
|
state: "open" | "closed" | "waiting",
|
||||||
) => void = (state: "open" | "closed" | "waiting") => {
|
) => {
|
||||||
if (state === "closed") {
|
if (state === "closed") {
|
||||||
_time_limit = null;
|
_time_limit = null;
|
||||||
stream_state = "closed";
|
stream_state = "closed";
|
||||||
@@ -92,12 +92,7 @@
|
|||||||
|
|
||||||
async function access_webcam(): Promise<void> {
|
async function access_webcam(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
get_video_stream(
|
get_video_stream(include_audio, video_source, null, track_constraints)
|
||||||
include_audio,
|
|
||||||
video_source,
|
|
||||||
null,
|
|
||||||
track_constraints,
|
|
||||||
)
|
|
||||||
.then(async (local_stream) => {
|
.then(async (local_stream) => {
|
||||||
webcam_accessed = true;
|
webcam_accessed = true;
|
||||||
available_video_devices = await get_devices();
|
available_video_devices = await get_devices();
|
||||||
@@ -112,16 +107,12 @@
|
|||||||
.map((track) => track.getSettings()?.deviceId)[0];
|
.map((track) => track.getSettings()?.deviceId)[0];
|
||||||
|
|
||||||
selected_device = used_devices
|
selected_device = used_devices
|
||||||
? devices.find(
|
? devices.find((device) => device.deviceId === used_devices) ||
|
||||||
(device) => device.deviceId === used_devices,
|
available_video_devices[0]
|
||||||
) || available_video_devices[0]
|
|
||||||
: available_video_devices[0];
|
: available_video_devices[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
||||||
!navigator.mediaDevices ||
|
|
||||||
!navigator.mediaDevices.getUserMedia
|
|
||||||
) {
|
|
||||||
dispatch("error", i18n("image.no_webcam_support"));
|
dispatch("error", i18n("image.no_webcam_support"));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -321,8 +312,7 @@
|
|||||||
{#each available_video_devices as device}
|
{#each available_video_devices as device}
|
||||||
<option
|
<option
|
||||||
value={device.deviceId}
|
value={device.deviceId}
|
||||||
selected={selected_device.deviceId ===
|
selected={selected_device.deviceId === device.deviceId}
|
||||||
device.deviceId}
|
|
||||||
>
|
>
|
||||||
{device.label}
|
{device.label}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
export let icon = Webcam;
|
export let icon = Webcam;
|
||||||
$: text = icon === Webcam ? "Click to Access Webcam" : "Click to Access Microphone";
|
$: text =
|
||||||
|
icon === Webcam ? "Click to Access Webcam" : "Click to Access Microphone";
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
click: undefined;
|
click: undefined;
|
||||||
|
|||||||
@@ -105,7 +105,11 @@ export async function start(
|
|||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_offer(server_fn: any, body, reject_cb: (msg: object) => void = () => { }): Promise<object> {
|
function make_offer(
|
||||||
|
server_fn: any,
|
||||||
|
body,
|
||||||
|
reject_cb: (msg: object) => void = () => {},
|
||||||
|
): Promise<object> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
server_fn(body).then((data) => {
|
server_fn(body).then((data) => {
|
||||||
console.debug("data", data);
|
console.debug("data", data);
|
||||||
@@ -150,11 +154,15 @@ async function negotiate(
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
var offer = pc.localDescription;
|
var offer = pc.localDescription;
|
||||||
return make_offer(server_fn, {
|
return make_offer(
|
||||||
|
server_fn,
|
||||||
|
{
|
||||||
sdp: offer.sdp,
|
sdp: offer.sdp,
|
||||||
type: offer.type,
|
type: offer.type,
|
||||||
webrtc_id: webrtc_id,
|
webrtc_id: webrtc_id,
|
||||||
}, reject_cb);
|
},
|
||||||
|
reject_cb,
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
Reference in New Issue
Block a user