diff --git a/.gitignore b/.gitignore
index bac4de2..199ab27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,4 +17,5 @@ demo/scratch
.vscode
.DS_Store
test/
-.venv*
\ No newline at end of file
+.venv*
+.env
\ No newline at end of file
diff --git a/backend/fastrtc/stream.py b/backend/fastrtc/stream.py
index 52e3227..96966b0 100644
--- a/backend/fastrtc/stream.py
+++ b/backend/fastrtc/stream.py
@@ -42,6 +42,8 @@ class UIArgs(TypedDict):
"""Color of the icon button. Default is var(--color-accent) of the demo theme."""
pulse_color: NotRequired[str]
"""Color of the pulse animation. Default is var(--color-accent) of the demo theme."""
+ icon_radius: NotRequired[int]
+ """Border radius of the icon button expressed as a percentage of the button size. Default is 50%."""
class Stream(WebRTCConnectionMixin):
@@ -322,6 +324,7 @@ class Stream(WebRTCConnectionMixin):
icon=ui_args.get("icon"),
icon_button_color=ui_args.get("icon_button_color"),
pulse_color=ui_args.get("pulse_color"),
+ icon_radius=ui_args.get("icon_radius"),
)
for component in additional_output_components:
if component not in same_components:
@@ -358,6 +361,10 @@ class Stream(WebRTCConnectionMixin):
rtc_configuration=self.rtc_configuration,
mode="send-receive",
modality="audio",
+ icon=ui_args.get("icon"),
+ icon_button_color=ui_args.get("icon_button_color"),
+ pulse_color=ui_args.get("pulse_color"),
+ icon_radius=ui_args.get("icon_radius"),
)
for component in additional_input_components:
if component not in same_components:
@@ -400,6 +407,7 @@ class Stream(WebRTCConnectionMixin):
icon=ui_args.get("icon"),
icon_button_color=ui_args.get("icon_button_color"),
pulse_color=ui_args.get("pulse_color"),
+ icon_radius=ui_args.get("icon_radius"),
)
for component in additional_input_components:
if component not in same_components:
@@ -443,6 +451,7 @@ class Stream(WebRTCConnectionMixin):
icon=ui_args.get("icon"),
icon_button_color=ui_args.get("icon_button_color"),
pulse_color=ui_args.get("pulse_color"),
+ icon_radius=ui_args.get("icon_radius"),
)
for component in additional_input_components:
if component not in same_components:
@@ -552,6 +561,7 @@ class Stream(WebRTCConnectionMixin):
port: int = 8000,
**kwargs,
):
+ import atexit
import secrets
import threading
import time
@@ -563,7 +573,6 @@ class Stream(WebRTCConnectionMixin):
from gradio.networking import setup_tunnel
from gradio.tunneling import CURRENT_TUNNELS
from huggingface_hub import get_token
- import atexit
app = FastAPI()
diff --git a/backend/fastrtc/utils.py b/backend/fastrtc/utils.py
index 1788574..e11a8cc 100644
--- a/backend/fastrtc/utils.py
+++ b/backend/fastrtc/utils.py
@@ -1,14 +1,15 @@
import asyncio
import fractions
+import functools
+import inspect
import io
import json
import logging
import tempfile
+import traceback
from contextvars import ContextVar
from typing import Any, Callable, Literal, Protocol, TypedDict, cast
-import functools
-import traceback
-import inspect
+
import av
import numpy as np
from numpy.typing import NDArray
diff --git a/backend/fastrtc/webrtc.py b/backend/fastrtc/webrtc.py
index a678e87..0129c92 100644
--- a/backend/fastrtc/webrtc.py
+++ b/backend/fastrtc/webrtc.py
@@ -87,6 +87,7 @@ class WebRTC(Component, WebRTCConnectionMixin):
icon: str | None = None,
icon_button_color: str | None = None,
pulse_color: str | None = None,
+ icon_radius: int | None = None,
button_labels: dict | None = None,
):
"""
@@ -119,6 +120,7 @@ class WebRTC(Component, WebRTCConnectionMixin):
icon_button_color: Color of the icon button. Default is var(--color-accent) of the demo theme.
pulse_color: Color of the pulse animation. Default is var(--color-accent) of the demo theme.
button_labels: Text to display on the audio or video start, stop, waiting buttons. Dict with keys "start", "stop", "waiting" mapping to the text to display on the buttons.
+ icon_radius: Border radius of the icon button expressed as a percentage of the button size. Default is 50%
"""
self.time_limit = time_limit
self.height = height
@@ -129,6 +131,7 @@ class WebRTC(Component, WebRTCConnectionMixin):
self.mode = mode
self.modality = modality
self.icon_button_color = icon_button_color
+ self.icon_radius = icon_radius
self.pulse_color = pulse_color
self.rtp_params = rtp_params or {}
self.button_labels = {
diff --git a/backend/fastrtc/webrtc_connection_mixin.py b/backend/fastrtc/webrtc_connection_mixin.py
index 8407bf0..7e03e46 100644
--- a/backend/fastrtc/webrtc_connection_mixin.py
+++ b/backend/fastrtc/webrtc_connection_mixin.py
@@ -149,14 +149,14 @@ class WebRTCConnectionMixin:
if isinstance(self.event_handler, StreamHandlerBase):
handler = self.event_handler.copy()
- handler.emit = webrtc_error_handler(handler.emit)
- handler.receive = webrtc_error_handler(handler.receive)
- handler.start_up = webrtc_error_handler(handler.start_up)
- handler.shutdown = webrtc_error_handler(handler.shutdown)
+ handler.emit = webrtc_error_handler(handler.emit) # type: ignore
+ handler.receive = webrtc_error_handler(handler.receive) # type: ignore
+ handler.start_up = webrtc_error_handler(handler.start_up) # type: ignore
+ handler.shutdown = webrtc_error_handler(handler.shutdown) # type: ignore
if hasattr(handler, "video_receive"):
- handler.video_receive = webrtc_error_handler(handler.video_receive)
+ handler.video_receive = webrtc_error_handler(handler.video_receive) # type: ignore
if hasattr(handler, "video_emit"):
- handler.video_emit = webrtc_error_handler(handler.video_emit)
+ handler.video_emit = webrtc_error_handler(handler.video_emit) # type: ignore
else:
handler = webrtc_error_handler(cast(Callable, self.event_handler))
diff --git a/demo/gemini_audio_video/app.py b/demo/gemini_audio_video/app.py
index 4a9a457..f8e01a7 100644
--- a/demo/gemini_audio_video/app.py
+++ b/demo/gemini_audio_video/app.py
@@ -5,16 +5,16 @@ import time
from io import BytesIO
import gradio as gr
-from gradio.utils import get_space
import numpy as np
-from google import genai
from dotenv import load_dotenv
from fastrtc import (
AsyncAudioVideoStreamHandler,
Stream,
- get_twilio_turn_credentials,
WebRTC,
+ get_twilio_turn_credentials,
)
+from google import genai
+from gradio.utils import get_space
from PIL import Image
load_dotenv()
diff --git a/frontend/Index.svelte b/frontend/Index.svelte
index a28ee42..e458cb1 100644
--- a/frontend/Index.svelte
+++ b/frontend/Index.svelte
@@ -38,6 +38,7 @@
export let icon: string | undefined = undefined;
export let icon_button_color: string = "var(--color-accent)";
export let pulse_color: string = "var(--color-accent)";
+ export let icon_radius: number = 50;
const on_change_cb = (msg: "change" | "tick" | any) => {
if (
@@ -124,6 +125,7 @@
{icon}
{icon_button_color}
{pulse_color}
+ {icon_radius}
i18n={gradio.i18n}
on:tick={() => gradio.dispatch("tick")}
on:error={({ detail }) => gradio.dispatch("error", detail)}
@@ -178,6 +180,7 @@
{icon}
{reject_cb}
{icon_button_color}
+ {icon_radius}
{pulse_color}
{button_labels}
on:tick={() => gradio.dispatch("tick")}
diff --git a/frontend/shared/AudioWave.svelte b/frontend/shared/AudioWave.svelte
index 8372fb9..9f99dcd 100644
--- a/frontend/shared/AudioWave.svelte
+++ b/frontend/shared/AudioWave.svelte
@@ -11,6 +11,7 @@
export let icon_button_color: string = "var(--color-accent)";
export let pulse_color: string = "var(--color-accent)";
export let pending: boolean = false;
+ export let icon_radius: number = 50;
let audioContext: AudioContext;
let analyser: AnalyserNode;
@@ -34,6 +35,7 @@
});
function setupAudioContext() {
+ // @ts-ignore
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
const source = audioContext.createMediaStreamSource(
@@ -58,6 +60,7 @@
);
for (let i = 0; i < bars.length; i++) {
const barHeight = (dataArray[i] / 255) * 2;
+ // @ts-ignore
bars[i].style.transform = `scaleY(${Math.max(0.1, barHeight)})`;
}
@@ -78,6 +81,7 @@
{pulse_color}
{icon}
{icon_button_color}
+ {icon_radius}
{audio_source_callback}
/>
diff --git a/frontend/shared/InteractiveAudio.svelte b/frontend/shared/InteractiveAudio.svelte
index 2a4f011..2611f6a 100644
--- a/frontend/shared/InteractiveAudio.svelte
+++ b/frontend/shared/InteractiveAudio.svelte
@@ -33,6 +33,7 @@
export let icon: string | undefined = undefined;
export let icon_button_color: string = "var(--color-accent)";
export let pulse_color: string = "var(--color-accent)";
+ export let icon_radius: number = 50;
export let button_labels: { start: string; stop: string; waiting: string };
let pending = false;
@@ -291,6 +292,7 @@
{icon_button_color}
{pulse_color}
{pending}
+ {icon_radius}
/>