Files
gradio-webrtc/docs/userguide/webrtc_docs.md
Freddy Boulton 853d6a06b5 Rebrand to FastRTC (#60)
* Add code

* add code

* add code

* Rename messages

* rename

* add code

* Add demo

* docs + demos + bug fixes

* add code

* styles

* user guide

* Styles

* Add code

* misc docs updates

* print nit

* whisper + pr

* url for images

* whsiper update

* Fix bugs

* remove demo files

* version number

* Fix pypi readme

* Fix

* demos

* Add llama code editor

* Update llama code editor and object detection cookbook

* Add more cookbook demos

* add code

* Fix links for PR deploys

* add code

* Fix the install

* add tts

* TTS docs

* Typo

* Pending bubbles for reply on pause

* Stream redesign (#63)

* better error handling

* Websocket error handling

* add code

---------

Co-authored-by: Freddy Boulton <freddyboulton@hf-freddy.local>

* remove docs from dist

* Some docs typos

* more typos

* upload changes + docs

* docs

* better phone

* update docs

* add code

* Make demos better

* fix docs + websocket start_up

* remove mention of FastAPI app

* fastphone tweaks

* add code

* ReplyOnStopWord fixes

* Fix cookbook

* Fix pypi readme

* add code

* bump versions

* sambanova cookbook

* Fix tags

* Llm voice chat

* kyutai tag

* Add error message to all index.html

* STT module uses Moonshine

* Not required from typing extensions

* fix llm voice chat

* Add vpn warning

* demo fixes

* demos

* Add more ui args and gemini audio-video

* update cookbook

* version 9

---------

Co-authored-by: Freddy Boulton <freddyboulton@hf-freddy.local>
2025-02-24 01:13:42 -05:00

160 lines
4.9 KiB
Markdown

# FastRTC Docs
## Connecting
To connect to the server, you need to create a new RTCPeerConnection object and call the `setupWebRTC` function below.
{% if mode in ["send-receive", "receive"] %}
This code snippet assumes there is an html element with an id of `{{ modality }}_output_component_id` where the output will be displayed. It should be {{ "a `<audio>`" if modality == "audio" else "an `<video>`"}} element.
{% endif %}
```js
// pass any rtc_configuration params here
const pc = new RTCPeerConnection();
{% if mode in ["send-receive", "receive"] %}
const {{modality}}_output_component = document.getElementById("{{modality}}_output_component_id");
{% endif %}
async function setupWebRTC(peerConnection) {
{%- if mode in ["send-receive", "send"] -%}
// Get {{modality}} stream from webcam
const stream = await navigator.mediaDevices.getUserMedia({
{{modality}}: true,
})
{%- endif -%}
{% if mode == "send-receive" %}
// Send {{ self.modality }} stream to server
stream.getTracks().forEach(async (track) => {
const sender = pc.addTrack(track, stream);
})
{% elif mode == "send" %}
// Receive {self.modality} stream from server
pc.addTransceiver({{modality}}, { direction: "recvonly" })
{%- endif -%}
{% if mode in ["send-receive", "receive"] %}
peerConnection.addEventListener("track", (evt) => {
if ({{modality}}_output_component &&
{{modality}}_output_component.srcObject !== evt.streams[0]) {
{{modality}}_output_component.srcObject = evt.streams[0];
}
});
{% endif %}
// Create data channel (needed!)
const dataChannel = peerConnection.createDataChannel("text");
// Create and send offer
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
// Send offer to server
const response = await fetch('/webrtc/offer', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sdp: offer.sdp,
type: offer.type,
webrtc_id: Math.random().toString(36).substring(7)
})
});
// Handle server response
const serverResponse = await response.json();
await peerConnection.setRemoteDescription(serverResponse);
}
```
{%if additional_inputs %}
## Sending Input Data
Your python handler can request additional data from the frontend by calling the `fetch_args()` method (see [here](#add docs)).
This will send a `send_input` message over the WebRTC data channel.
Upon receiving this message, you should trigger the `set_input` hook of your stream.
A simple way to do this is with a `POST` request.
```python
@stream.post("/input_hook")
def _(data: PydanticBody):
stream.set_inputs(data.webrtc_id, data.inputs)
```
And then in your client code:
```js
const data_channel = peerConnection.createDataChannel("text");
data_channel.onmessage = (event) => {
event_json = JSON.parse(event.data);
if (event_json.type === "send_input") {
fetch('/input_hook', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: inputs
}
)
};
};
```
The `set_inputs` hook will set the `latest_args` property of your stream to whatever the second argument is.
NOTE: It is completely up to you how you want to call the `set_inputs` hook.
Here we use a `POST` request but you can use a websocket or any other protocol.
{% endif %}
{% if additional_outputs %}
## Fetching Output Data
Your python handler can send additional data to the front end by returning or yielding `AdditionalOutputs(...)`. See the [docs](https://freddyaboulton.github.io/gradio-webrtc/user-guide/#additional-outputs).
Your front end can fetch these outputs by calling the `get_outputs` hook of the `Stream`.
Here is an example using `server-sent-events`:
```python
@stream.get("/outputs")
def _(webrtc_id: str)
async def get_outputs():
while True:
for output in stream.get_output(webrtc_id):
# Serialize to a string prior to this step
yield f"data: {output}\n\n"
await
return StreamingResponse(get_outputs(), media_type="text/event-stream")
```
NOTE: It is completely up to you how you want to call the `get_output` hook.
Here we use a `server-sent-events` but you can use whatever protocol you want!
{% endif %}
## Stopping
You can stop the stream by calling the following function:
```js
function stop(pc) {
// close transceivers
if (pc.getTransceivers) {
pc.getTransceivers().forEach((transceiver) => {
if (transceiver.stop) {
transceiver.stop();
}
});
}
// close local audio / video
if (pc.getSenders()) {
pc.getSenders().forEach((sender) => {
if (sender.track && sender.track.stop) sender.track.stop();
});
}
// close peer connection
setTimeout(() => {
pc.close();
}, 500);
}
```