Spaces:
Runtime error
Runtime error
apply pre-commit
Browse files- README.md +1 -1
- app.py +16 -25
- app_allenai.py +19 -25
- app_cohere.py +1 -1
- app_gemini_voice.py +46 -55
- app_huggingface.py +23 -37
- app_lumaai.py +2 -2
- app_meta.py +1 -1
- app_mindsearch.py +2 -2
- app_paligemma.py +31 -51
- app_playai.py +3 -3
- app_showui.py +1 -1
- app_trellis.py +1 -1
- utils.py +1 -1
README.md
CHANGED
|
@@ -10,4 +10,4 @@ pinned: false
|
|
| 10 |
disable_embedding: true
|
| 11 |
---
|
| 12 |
|
| 13 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 10 |
disable_embedding: true
|
| 11 |
---
|
| 12 |
|
| 13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
CHANGED
|
@@ -1,34 +1,32 @@
|
|
| 1 |
-
from
|
| 2 |
-
|
| 3 |
|
| 4 |
# Import all demos
|
| 5 |
from app_cohere import demo as demo_cohere
|
| 6 |
-
from app_meta import demo as demo_meta
|
| 7 |
-
from app_lumaai import demo as demo_lumaai
|
| 8 |
-
from app_paligemma import demo as demo_paligemma
|
| 9 |
-
from app_replicate import demo as demo_replicate
|
| 10 |
-
from app_huggingface import demo as demo_huggingface
|
| 11 |
-
from app_playai import demo as demo_playai
|
| 12 |
-
from app_allenai import demo as demo_allenai
|
| 13 |
-
from app_claude import demo as demo_claude
|
| 14 |
from app_experimental import demo as demo_experimental
|
|
|
|
| 15 |
from app_fireworks import demo as demo_fireworks
|
| 16 |
from app_gemini import demo as demo_gemini
|
|
|
|
| 17 |
from app_groq import demo as demo_groq
|
|
|
|
| 18 |
from app_hyperbolic import demo as demo_hyperbolic
|
| 19 |
-
from
|
|
|
|
| 20 |
from app_mistral import demo as demo_mistral
|
| 21 |
from app_nvidia import demo as demo_nvidia
|
|
|
|
| 22 |
from app_openai import demo as demo_openai
|
|
|
|
| 23 |
from app_perplexity import demo as demo_perplexity
|
|
|
|
| 24 |
from app_qwen import demo as demo_qwen
|
|
|
|
| 25 |
from app_sambanova import demo as demo_sambanova
|
|
|
|
| 26 |
from app_together import demo as demo_together
|
| 27 |
from app_xai import demo as demo_grok
|
| 28 |
-
from
|
| 29 |
-
from app_omini import demo as demo_omini
|
| 30 |
-
from app_gemini_voice import demo as demo_gemini_voice
|
| 31 |
-
|
| 32 |
|
| 33 |
# Create mapping of providers to their demos
|
| 34 |
PROVIDERS = {
|
|
@@ -57,19 +55,12 @@ PROVIDERS = {
|
|
| 57 |
"Perplexity": demo_perplexity,
|
| 58 |
"Experimental": demo_experimental,
|
| 59 |
"Mistral": demo_mistral,
|
| 60 |
-
"NVIDIA": demo_nvidia
|
| 61 |
}
|
| 62 |
|
| 63 |
-
demo = get_app(
|
| 64 |
-
models=list(PROVIDERS.keys()),
|
| 65 |
-
default_model="Gemini",
|
| 66 |
-
src=PROVIDERS,
|
| 67 |
-
dropdown_label="Select Provider"
|
| 68 |
-
)
|
| 69 |
|
| 70 |
if __name__ == "__main__":
|
| 71 |
demo.queue(
|
| 72 |
api_open=False,
|
| 73 |
-
).launch(
|
| 74 |
-
show_api=False
|
| 75 |
-
)
|
|
|
|
| 1 |
+
from app_allenai import demo as demo_allenai
|
| 2 |
+
from app_claude import demo as demo_claude
|
| 3 |
|
| 4 |
# Import all demos
|
| 5 |
from app_cohere import demo as demo_cohere
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
from app_experimental import demo as demo_experimental
|
| 7 |
+
from app_fal import demo as demo_fal
|
| 8 |
from app_fireworks import demo as demo_fireworks
|
| 9 |
from app_gemini import demo as demo_gemini
|
| 10 |
+
from app_gemini_voice import demo as demo_gemini_voice
|
| 11 |
from app_groq import demo as demo_groq
|
| 12 |
+
from app_huggingface import demo as demo_huggingface
|
| 13 |
from app_hyperbolic import demo as demo_hyperbolic
|
| 14 |
+
from app_lumaai import demo as demo_lumaai
|
| 15 |
+
from app_meta import demo as demo_meta
|
| 16 |
from app_mistral import demo as demo_mistral
|
| 17 |
from app_nvidia import demo as demo_nvidia
|
| 18 |
+
from app_omini import demo as demo_omini
|
| 19 |
from app_openai import demo as demo_openai
|
| 20 |
+
from app_paligemma import demo as demo_paligemma
|
| 21 |
from app_perplexity import demo as demo_perplexity
|
| 22 |
+
from app_playai import demo as demo_playai
|
| 23 |
from app_qwen import demo as demo_qwen
|
| 24 |
+
from app_replicate import demo as demo_replicate
|
| 25 |
from app_sambanova import demo as demo_sambanova
|
| 26 |
+
from app_showui import demo as demo_showui
|
| 27 |
from app_together import demo as demo_together
|
| 28 |
from app_xai import demo as demo_grok
|
| 29 |
+
from utils import get_app
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
# Create mapping of providers to their demos
|
| 32 |
PROVIDERS = {
|
|
|
|
| 55 |
"Perplexity": demo_perplexity,
|
| 56 |
"Experimental": demo_experimental,
|
| 57 |
"Mistral": demo_mistral,
|
| 58 |
+
"NVIDIA": demo_nvidia,
|
| 59 |
}
|
| 60 |
|
| 61 |
+
demo = get_app(models=list(PROVIDERS.keys()), default_model="Gemini", src=PROVIDERS, dropdown_label="Select Provider")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
if __name__ == "__main__":
|
| 64 |
demo.queue(
|
| 65 |
api_open=False,
|
| 66 |
+
).launch(show_api=False)
|
|
|
|
|
|
app_allenai.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
| 1 |
-
from gradio_client import Client
|
| 2 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
-
MODELS = {
|
| 5 |
-
"OLMo-2-1124-13B-Instruct": "akhaliq/olmo-anychat",
|
| 6 |
-
"Llama-3.1-Tulu-3-8B": "akhaliq/allen-test"
|
| 7 |
-
}
|
| 8 |
|
| 9 |
def create_chat_fn(client):
|
| 10 |
def chat(message, history):
|
|
@@ -16,51 +14,49 @@ def create_chat_fn(client):
|
|
| 16 |
top_k=40,
|
| 17 |
repetition_penalty=1.1,
|
| 18 |
top_p=0.95,
|
| 19 |
-
api_name="/chat"
|
| 20 |
)
|
| 21 |
return response
|
|
|
|
| 22 |
return chat
|
| 23 |
|
|
|
|
| 24 |
def set_client_for_session(model_name, request: gr.Request):
|
| 25 |
headers = {}
|
| 26 |
-
if request and hasattr(request,
|
| 27 |
-
x_ip_token = request.request.headers.get(
|
| 28 |
if x_ip_token:
|
| 29 |
headers["X-IP-Token"] = x_ip_token
|
| 30 |
-
|
| 31 |
return Client(MODELS[model_name], headers=headers)
|
| 32 |
|
|
|
|
| 33 |
def safe_chat_fn(message, history, client):
|
| 34 |
if client is None:
|
| 35 |
return "Error: Client not initialized. Please refresh the page."
|
| 36 |
return create_chat_fn(client)(message, history)
|
| 37 |
|
|
|
|
| 38 |
with gr.Blocks() as demo:
|
| 39 |
-
|
| 40 |
client = gr.State()
|
| 41 |
-
|
| 42 |
model_dropdown = gr.Dropdown(
|
| 43 |
-
choices=list(MODELS.keys()),
|
| 44 |
-
value="OLMo-2-1124-13B-Instruct",
|
| 45 |
-
label="Select Model",
|
| 46 |
-
interactive=True
|
| 47 |
-
)
|
| 48 |
-
|
| 49 |
-
chat_interface = gr.ChatInterface(
|
| 50 |
-
fn=safe_chat_fn,
|
| 51 |
-
additional_inputs=[client]
|
| 52 |
)
|
| 53 |
-
|
|
|
|
|
|
|
| 54 |
# Update client when model changes
|
| 55 |
def update_model(model_name, request):
|
| 56 |
return set_client_for_session(model_name, request)
|
| 57 |
-
|
| 58 |
model_dropdown.change(
|
| 59 |
fn=update_model,
|
| 60 |
inputs=[model_dropdown],
|
| 61 |
outputs=[client],
|
| 62 |
)
|
| 63 |
-
|
| 64 |
# Initialize client on page load
|
| 65 |
demo.load(
|
| 66 |
fn=set_client_for_session,
|
|
@@ -69,5 +65,3 @@ with gr.Blocks() as demo:
|
|
| 69 |
)
|
| 70 |
|
| 71 |
demo = demo
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
+
from gradio_client import Client
|
| 3 |
+
|
| 4 |
+
MODELS = {"OLMo-2-1124-13B-Instruct": "akhaliq/olmo-anychat", "Llama-3.1-Tulu-3-8B": "akhaliq/allen-test"}
|
| 5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
def create_chat_fn(client):
|
| 8 |
def chat(message, history):
|
|
|
|
| 14 |
top_k=40,
|
| 15 |
repetition_penalty=1.1,
|
| 16 |
top_p=0.95,
|
| 17 |
+
api_name="/chat",
|
| 18 |
)
|
| 19 |
return response
|
| 20 |
+
|
| 21 |
return chat
|
| 22 |
|
| 23 |
+
|
| 24 |
def set_client_for_session(model_name, request: gr.Request):
|
| 25 |
headers = {}
|
| 26 |
+
if request and hasattr(request, "request") and hasattr(request.request, "headers"):
|
| 27 |
+
x_ip_token = request.request.headers.get("x-ip-token")
|
| 28 |
if x_ip_token:
|
| 29 |
headers["X-IP-Token"] = x_ip_token
|
| 30 |
+
|
| 31 |
return Client(MODELS[model_name], headers=headers)
|
| 32 |
|
| 33 |
+
|
| 34 |
def safe_chat_fn(message, history, client):
|
| 35 |
if client is None:
|
| 36 |
return "Error: Client not initialized. Please refresh the page."
|
| 37 |
return create_chat_fn(client)(message, history)
|
| 38 |
|
| 39 |
+
|
| 40 |
with gr.Blocks() as demo:
|
| 41 |
+
|
| 42 |
client = gr.State()
|
| 43 |
+
|
| 44 |
model_dropdown = gr.Dropdown(
|
| 45 |
+
choices=list(MODELS.keys()), value="OLMo-2-1124-13B-Instruct", label="Select Model", interactive=True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
)
|
| 47 |
+
|
| 48 |
+
chat_interface = gr.ChatInterface(fn=safe_chat_fn, additional_inputs=[client])
|
| 49 |
+
|
| 50 |
# Update client when model changes
|
| 51 |
def update_model(model_name, request):
|
| 52 |
return set_client_for_session(model_name, request)
|
| 53 |
+
|
| 54 |
model_dropdown.change(
|
| 55 |
fn=update_model,
|
| 56 |
inputs=[model_dropdown],
|
| 57 |
outputs=[client],
|
| 58 |
)
|
| 59 |
+
|
| 60 |
# Initialize client on page load
|
| 61 |
demo.load(
|
| 62 |
fn=set_client_for_session,
|
|
|
|
| 65 |
)
|
| 66 |
|
| 67 |
demo = demo
|
|
|
|
|
|
app_cohere.py
CHANGED
|
@@ -18,4 +18,4 @@ demo = get_app(
|
|
| 18 |
)
|
| 19 |
|
| 20 |
if __name__ == "__main__":
|
| 21 |
-
demo.launch()
|
|
|
|
| 18 |
)
|
| 19 |
|
| 20 |
if __name__ == "__main__":
|
| 21 |
+
demo.launch()
|
app_gemini_voice.py
CHANGED
|
@@ -1,36 +1,41 @@
|
|
| 1 |
-
import gradio as gr
|
| 2 |
-
from gradio_webrtc import WebRTC, StreamHandler, get_twilio_turn_credentials
|
| 3 |
-
import websockets.sync.client
|
| 4 |
-
import numpy as np
|
| 5 |
-
import json
|
| 6 |
import base64
|
|
|
|
| 7 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
from dotenv import load_dotenv
|
|
|
|
|
|
|
| 9 |
|
| 10 |
class GeminiConfig:
|
| 11 |
def __init__(self):
|
| 12 |
load_dotenv()
|
| 13 |
self.api_key = self._get_api_key()
|
| 14 |
-
self.host =
|
| 15 |
-
self.model =
|
| 16 |
-
self.ws_url = f
|
| 17 |
|
| 18 |
def _get_api_key(self):
|
| 19 |
-
api_key = os.getenv(
|
| 20 |
if not api_key:
|
| 21 |
raise ValueError("GOOGLE_API_KEY not found in environment variables. Please set it in your .env file.")
|
| 22 |
return api_key
|
| 23 |
|
|
|
|
| 24 |
class AudioProcessor:
|
| 25 |
@staticmethod
|
| 26 |
def encode_audio(data, sample_rate):
|
| 27 |
-
encoded = base64.b64encode(data.tobytes()).decode(
|
| 28 |
return {
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
|
|
|
|
|
|
| 34 |
},
|
| 35 |
}
|
| 36 |
|
|
@@ -39,13 +44,10 @@ class AudioProcessor:
|
|
| 39 |
audio_data = base64.b64decode(data)
|
| 40 |
return np.frombuffer(audio_data, dtype=np.int16)
|
| 41 |
|
|
|
|
| 42 |
class GeminiHandler(StreamHandler):
|
| 43 |
-
def __init__(self,
|
| 44 |
-
|
| 45 |
-
output_sample_rate=24000,
|
| 46 |
-
output_frame_size=480) -> None:
|
| 47 |
-
super().__init__(expected_layout, output_sample_rate, output_frame_size,
|
| 48 |
-
input_sample_rate=24000)
|
| 49 |
self.config = GeminiConfig()
|
| 50 |
self.ws = None
|
| 51 |
self.all_output_data = None
|
|
@@ -55,18 +57,15 @@ class GeminiHandler(StreamHandler):
|
|
| 55 |
return GeminiHandler(
|
| 56 |
expected_layout=self.expected_layout,
|
| 57 |
output_sample_rate=self.output_sample_rate,
|
| 58 |
-
output_frame_size=self.output_frame_size
|
| 59 |
)
|
| 60 |
|
| 61 |
def _initialize_websocket(self):
|
| 62 |
try:
|
| 63 |
-
self.ws = websockets.sync.client.connect(
|
| 64 |
-
self.config.ws_url,
|
| 65 |
-
timeout=30
|
| 66 |
-
)
|
| 67 |
initial_request = {
|
| 68 |
-
|
| 69 |
-
|
| 70 |
}
|
| 71 |
}
|
| 72 |
self.ws.send(json.dumps(initial_request))
|
|
@@ -87,7 +86,7 @@ class GeminiHandler(StreamHandler):
|
|
| 87 |
_, array = frame
|
| 88 |
array = array.squeeze()
|
| 89 |
audio_message = self.audio_processor.encode_audio(array, self.output_sample_rate)
|
| 90 |
-
self.ws.send(json.dumps(audio_message))
|
| 91 |
except Exception as e:
|
| 92 |
print(f"Error in receive: {str(e)}")
|
| 93 |
if self.ws:
|
|
@@ -95,8 +94,8 @@ class GeminiHandler(StreamHandler):
|
|
| 95 |
self.ws = None
|
| 96 |
|
| 97 |
def _process_server_content(self, content):
|
| 98 |
-
for part in content.get(
|
| 99 |
-
data = part.get(
|
| 100 |
if data:
|
| 101 |
audio_array = self.audio_processor.process_audio_response(data)
|
| 102 |
if self.all_output_data is None:
|
|
@@ -105,9 +104,8 @@ class GeminiHandler(StreamHandler):
|
|
| 105 |
self.all_output_data = np.concatenate((self.all_output_data, audio_array))
|
| 106 |
|
| 107 |
while self.all_output_data.shape[-1] >= self.output_frame_size:
|
| 108 |
-
yield (self.output_sample_rate,
|
| 109 |
-
|
| 110 |
-
self.all_output_data = self.all_output_data[self.output_frame_size:]
|
| 111 |
|
| 112 |
def generator(self):
|
| 113 |
while True:
|
|
@@ -120,8 +118,8 @@ class GeminiHandler(StreamHandler):
|
|
| 120 |
message = self.ws.recv(timeout=5)
|
| 121 |
msg = json.loads(message)
|
| 122 |
|
| 123 |
-
if
|
| 124 |
-
content = msg[
|
| 125 |
yield from self._process_server_content(content)
|
| 126 |
except TimeoutError:
|
| 127 |
print("Timeout waiting for server response")
|
|
@@ -133,7 +131,7 @@ class GeminiHandler(StreamHandler):
|
|
| 133 |
def emit(self) -> tuple[int, np.ndarray] | None:
|
| 134 |
if not self.ws:
|
| 135 |
return None
|
| 136 |
-
if not hasattr(self,
|
| 137 |
self._generator = self.generator()
|
| 138 |
try:
|
| 139 |
return next(self._generator)
|
|
@@ -142,8 +140,8 @@ class GeminiHandler(StreamHandler):
|
|
| 142 |
return None
|
| 143 |
|
| 144 |
def reset(self) -> None:
|
| 145 |
-
if hasattr(self,
|
| 146 |
-
delattr(self,
|
| 147 |
self.all_output_data = None
|
| 148 |
|
| 149 |
def shutdown(self) -> None:
|
|
@@ -159,6 +157,7 @@ class GeminiHandler(StreamHandler):
|
|
| 159 |
print(f"Connection check failed: {str(e)}")
|
| 160 |
return False
|
| 161 |
|
|
|
|
| 162 |
class GeminiVoiceChat:
|
| 163 |
def __init__(self):
|
| 164 |
load_dotenv()
|
|
@@ -166,38 +165,30 @@ class GeminiVoiceChat:
|
|
| 166 |
|
| 167 |
def _create_interface(self):
|
| 168 |
with gr.Blocks() as demo:
|
| 169 |
-
gr.HTML(
|
|
|
|
| 170 |
<div style='text-align: center'>
|
| 171 |
<h1>Gemini 2.0 Voice Chat</h1>
|
| 172 |
<p>Speak with Gemini using real-time audio streaming</p>
|
| 173 |
</div>
|
| 174 |
-
"""
|
|
|
|
| 175 |
|
| 176 |
webrtc = WebRTC(
|
| 177 |
label="Conversation",
|
| 178 |
modality="audio",
|
| 179 |
mode="send-receive",
|
| 180 |
-
rtc_configuration=get_twilio_turn_credentials()
|
| 181 |
)
|
| 182 |
|
| 183 |
-
webrtc.stream(
|
| 184 |
-
GeminiHandler(),
|
| 185 |
-
inputs=[webrtc],
|
| 186 |
-
outputs=[webrtc],
|
| 187 |
-
time_limit=90,
|
| 188 |
-
concurrency_limit=10
|
| 189 |
-
)
|
| 190 |
return demo
|
| 191 |
|
| 192 |
def launch(self):
|
| 193 |
self.demo.launch()
|
| 194 |
-
# Create and expose the demo instance
|
| 195 |
-
def demo():
|
| 196 |
-
chat = GeminiVoiceChat()
|
| 197 |
-
return chat.demo
|
| 198 |
|
| 199 |
-
|
| 200 |
-
demo =
|
| 201 |
|
| 202 |
if __name__ == "__main__":
|
| 203 |
demo.launch(server_name="0.0.0.0")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import base64
|
| 2 |
+
import json
|
| 3 |
import os
|
| 4 |
+
|
| 5 |
+
import gradio as gr
|
| 6 |
+
import numpy as np
|
| 7 |
+
import websockets.sync.client
|
| 8 |
from dotenv import load_dotenv
|
| 9 |
+
from gradio_webrtc import StreamHandler, WebRTC, get_twilio_turn_credentials
|
| 10 |
+
|
| 11 |
|
| 12 |
class GeminiConfig:
|
| 13 |
def __init__(self):
|
| 14 |
load_dotenv()
|
| 15 |
self.api_key = self._get_api_key()
|
| 16 |
+
self.host = "generativelanguage.googleapis.com"
|
| 17 |
+
self.model = "models/gemini-2.0-flash-exp"
|
| 18 |
+
self.ws_url = f"wss://{self.host}/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key={self.api_key}"
|
| 19 |
|
| 20 |
def _get_api_key(self):
|
| 21 |
+
api_key = os.getenv("GOOGLE_API_KEY")
|
| 22 |
if not api_key:
|
| 23 |
raise ValueError("GOOGLE_API_KEY not found in environment variables. Please set it in your .env file.")
|
| 24 |
return api_key
|
| 25 |
|
| 26 |
+
|
| 27 |
class AudioProcessor:
|
| 28 |
@staticmethod
|
| 29 |
def encode_audio(data, sample_rate):
|
| 30 |
+
encoded = base64.b64encode(data.tobytes()).decode("UTF-8")
|
| 31 |
return {
|
| 32 |
+
"realtimeInput": {
|
| 33 |
+
"mediaChunks": [
|
| 34 |
+
{
|
| 35 |
+
"mimeType": f"audio/pcm;rate={sample_rate}",
|
| 36 |
+
"data": encoded,
|
| 37 |
+
}
|
| 38 |
+
],
|
| 39 |
},
|
| 40 |
}
|
| 41 |
|
|
|
|
| 44 |
audio_data = base64.b64decode(data)
|
| 45 |
return np.frombuffer(audio_data, dtype=np.int16)
|
| 46 |
|
| 47 |
+
|
| 48 |
class GeminiHandler(StreamHandler):
|
| 49 |
+
def __init__(self, expected_layout="mono", output_sample_rate=24000, output_frame_size=480) -> None:
|
| 50 |
+
super().__init__(expected_layout, output_sample_rate, output_frame_size, input_sample_rate=24000)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
self.config = GeminiConfig()
|
| 52 |
self.ws = None
|
| 53 |
self.all_output_data = None
|
|
|
|
| 57 |
return GeminiHandler(
|
| 58 |
expected_layout=self.expected_layout,
|
| 59 |
output_sample_rate=self.output_sample_rate,
|
| 60 |
+
output_frame_size=self.output_frame_size,
|
| 61 |
)
|
| 62 |
|
| 63 |
def _initialize_websocket(self):
|
| 64 |
try:
|
| 65 |
+
self.ws = websockets.sync.client.connect(self.config.ws_url, timeout=30)
|
|
|
|
|
|
|
|
|
|
| 66 |
initial_request = {
|
| 67 |
+
"setup": {
|
| 68 |
+
"model": self.config.model,
|
| 69 |
}
|
| 70 |
}
|
| 71 |
self.ws.send(json.dumps(initial_request))
|
|
|
|
| 86 |
_, array = frame
|
| 87 |
array = array.squeeze()
|
| 88 |
audio_message = self.audio_processor.encode_audio(array, self.output_sample_rate)
|
| 89 |
+
self.ws.send(json.dumps(audio_message)) # type: ignore
|
| 90 |
except Exception as e:
|
| 91 |
print(f"Error in receive: {str(e)}")
|
| 92 |
if self.ws:
|
|
|
|
| 94 |
self.ws = None
|
| 95 |
|
| 96 |
def _process_server_content(self, content):
|
| 97 |
+
for part in content.get("parts", []):
|
| 98 |
+
data = part.get("inlineData", {}).get("data", "")
|
| 99 |
if data:
|
| 100 |
audio_array = self.audio_processor.process_audio_response(data)
|
| 101 |
if self.all_output_data is None:
|
|
|
|
| 104 |
self.all_output_data = np.concatenate((self.all_output_data, audio_array))
|
| 105 |
|
| 106 |
while self.all_output_data.shape[-1] >= self.output_frame_size:
|
| 107 |
+
yield (self.output_sample_rate, self.all_output_data[: self.output_frame_size].reshape(1, -1))
|
| 108 |
+
self.all_output_data = self.all_output_data[self.output_frame_size :]
|
|
|
|
| 109 |
|
| 110 |
def generator(self):
|
| 111 |
while True:
|
|
|
|
| 118 |
message = self.ws.recv(timeout=5)
|
| 119 |
msg = json.loads(message)
|
| 120 |
|
| 121 |
+
if "serverContent" in msg:
|
| 122 |
+
content = msg["serverContent"].get("modelTurn", {})
|
| 123 |
yield from self._process_server_content(content)
|
| 124 |
except TimeoutError:
|
| 125 |
print("Timeout waiting for server response")
|
|
|
|
| 131 |
def emit(self) -> tuple[int, np.ndarray] | None:
|
| 132 |
if not self.ws:
|
| 133 |
return None
|
| 134 |
+
if not hasattr(self, "_generator"):
|
| 135 |
self._generator = self.generator()
|
| 136 |
try:
|
| 137 |
return next(self._generator)
|
|
|
|
| 140 |
return None
|
| 141 |
|
| 142 |
def reset(self) -> None:
|
| 143 |
+
if hasattr(self, "_generator"):
|
| 144 |
+
delattr(self, "_generator")
|
| 145 |
self.all_output_data = None
|
| 146 |
|
| 147 |
def shutdown(self) -> None:
|
|
|
|
| 157 |
print(f"Connection check failed: {str(e)}")
|
| 158 |
return False
|
| 159 |
|
| 160 |
+
|
| 161 |
class GeminiVoiceChat:
|
| 162 |
def __init__(self):
|
| 163 |
load_dotenv()
|
|
|
|
| 165 |
|
| 166 |
def _create_interface(self):
|
| 167 |
with gr.Blocks() as demo:
|
| 168 |
+
gr.HTML(
|
| 169 |
+
"""
|
| 170 |
<div style='text-align: center'>
|
| 171 |
<h1>Gemini 2.0 Voice Chat</h1>
|
| 172 |
<p>Speak with Gemini using real-time audio streaming</p>
|
| 173 |
</div>
|
| 174 |
+
"""
|
| 175 |
+
)
|
| 176 |
|
| 177 |
webrtc = WebRTC(
|
| 178 |
label="Conversation",
|
| 179 |
modality="audio",
|
| 180 |
mode="send-receive",
|
| 181 |
+
rtc_configuration=get_twilio_turn_credentials(),
|
| 182 |
)
|
| 183 |
|
| 184 |
+
webrtc.stream(GeminiHandler(), inputs=[webrtc], outputs=[webrtc], time_limit=90, concurrency_limit=10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
return demo
|
| 186 |
|
| 187 |
def launch(self):
|
| 188 |
self.demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
+
|
| 191 |
+
demo = GeminiVoiceChat().demo
|
| 192 |
|
| 193 |
if __name__ == "__main__":
|
| 194 |
demo.launch(server_name="0.0.0.0")
|
app_huggingface.py
CHANGED
|
@@ -1,21 +1,18 @@
|
|
| 1 |
-
from gradio_client import Client, handle_file
|
| 2 |
import gradio as gr
|
| 3 |
-
import
|
| 4 |
|
|
|
|
| 5 |
|
| 6 |
-
MODELS = {
|
| 7 |
-
"SmolVLM-Instruct": "akhaliq/SmolVLM-Instruct"
|
| 8 |
-
}
|
| 9 |
|
| 10 |
def create_chat_fn(client):
|
| 11 |
def chat(message, history):
|
| 12 |
# Extract text and files from the message
|
| 13 |
text = message.get("text", "")
|
| 14 |
files = message.get("files", [])
|
| 15 |
-
|
| 16 |
# Handle file uploads if present
|
| 17 |
processed_files = [handle_file(f) for f in files]
|
| 18 |
-
|
| 19 |
response = client.predict(
|
| 20 |
message={"text": text, "files": processed_files},
|
| 21 |
system_prompt="You are a helpful AI assistant.",
|
|
@@ -24,20 +21,23 @@ def create_chat_fn(client):
|
|
| 24 |
top_k=40,
|
| 25 |
repetition_penalty=1.1,
|
| 26 |
top_p=0.95,
|
| 27 |
-
api_name="/chat"
|
| 28 |
)
|
| 29 |
return response
|
|
|
|
| 30 |
return chat
|
| 31 |
|
|
|
|
| 32 |
def set_client_for_session(model_name, request: gr.Request):
|
| 33 |
headers = {}
|
| 34 |
-
if request and hasattr(request,
|
| 35 |
-
x_ip_token = request.headers.get(
|
| 36 |
if x_ip_token:
|
| 37 |
headers["X-IP-Token"] = x_ip_token
|
| 38 |
-
|
| 39 |
return Client(MODELS[model_name], headers=headers)
|
| 40 |
|
|
|
|
| 41 |
def safe_chat_fn(message, history, client):
|
| 42 |
if client is None:
|
| 43 |
return "Error: Client not initialized. Please refresh the page."
|
|
@@ -47,36 +47,22 @@ def safe_chat_fn(message, history, client):
|
|
| 47 |
print(f"Error during chat: {str(e)}")
|
| 48 |
return f"Error during chat: {str(e)}"
|
| 49 |
|
|
|
|
| 50 |
with gr.Blocks() as demo:
|
| 51 |
-
|
| 52 |
client = gr.State()
|
| 53 |
-
|
| 54 |
model_dropdown = gr.Dropdown(
|
| 55 |
-
choices=list(MODELS.keys()),
|
| 56 |
-
value="SmolVLM-Instruct",
|
| 57 |
-
label="Select Model",
|
| 58 |
-
interactive=True
|
| 59 |
-
)
|
| 60 |
-
|
| 61 |
-
chat_interface = gr.ChatInterface(
|
| 62 |
-
fn=safe_chat_fn,
|
| 63 |
-
additional_inputs=[client],
|
| 64 |
-
multimodal=True
|
| 65 |
)
|
| 66 |
-
|
|
|
|
|
|
|
| 67 |
# Update client when model changes
|
| 68 |
-
model_dropdown.change(
|
| 69 |
-
fn=set_client_for_session,
|
| 70 |
-
inputs=[model_dropdown],
|
| 71 |
-
outputs=[client]
|
| 72 |
-
)
|
| 73 |
-
|
| 74 |
-
# Initialize client on page load
|
| 75 |
-
demo.load(
|
| 76 |
-
fn=set_client_for_session,
|
| 77 |
-
inputs=[gr.State("SmolVLM-Instruct")],
|
| 78 |
-
outputs=[client]
|
| 79 |
-
)
|
| 80 |
|
| 81 |
-
|
|
|
|
| 82 |
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
+
from gradio_client import Client, handle_file
|
| 3 |
|
| 4 |
+
MODELS = {"SmolVLM-Instruct": "akhaliq/SmolVLM-Instruct"}
|
| 5 |
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
def create_chat_fn(client):
|
| 8 |
def chat(message, history):
|
| 9 |
# Extract text and files from the message
|
| 10 |
text = message.get("text", "")
|
| 11 |
files = message.get("files", [])
|
| 12 |
+
|
| 13 |
# Handle file uploads if present
|
| 14 |
processed_files = [handle_file(f) for f in files]
|
| 15 |
+
|
| 16 |
response = client.predict(
|
| 17 |
message={"text": text, "files": processed_files},
|
| 18 |
system_prompt="You are a helpful AI assistant.",
|
|
|
|
| 21 |
top_k=40,
|
| 22 |
repetition_penalty=1.1,
|
| 23 |
top_p=0.95,
|
| 24 |
+
api_name="/chat",
|
| 25 |
)
|
| 26 |
return response
|
| 27 |
+
|
| 28 |
return chat
|
| 29 |
|
| 30 |
+
|
| 31 |
def set_client_for_session(model_name, request: gr.Request):
|
| 32 |
headers = {}
|
| 33 |
+
if request and hasattr(request, "headers"):
|
| 34 |
+
x_ip_token = request.headers.get("x-ip-token")
|
| 35 |
if x_ip_token:
|
| 36 |
headers["X-IP-Token"] = x_ip_token
|
| 37 |
+
|
| 38 |
return Client(MODELS[model_name], headers=headers)
|
| 39 |
|
| 40 |
+
|
| 41 |
def safe_chat_fn(message, history, client):
|
| 42 |
if client is None:
|
| 43 |
return "Error: Client not initialized. Please refresh the page."
|
|
|
|
| 47 |
print(f"Error during chat: {str(e)}")
|
| 48 |
return f"Error during chat: {str(e)}"
|
| 49 |
|
| 50 |
+
|
| 51 |
with gr.Blocks() as demo:
|
| 52 |
+
|
| 53 |
client = gr.State()
|
| 54 |
+
|
| 55 |
model_dropdown = gr.Dropdown(
|
| 56 |
+
choices=list(MODELS.keys()), value="SmolVLM-Instruct", label="Select Model", interactive=True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
)
|
| 58 |
+
|
| 59 |
+
chat_interface = gr.ChatInterface(fn=safe_chat_fn, additional_inputs=[client], multimodal=True)
|
| 60 |
+
|
| 61 |
# Update client when model changes
|
| 62 |
+
model_dropdown.change(fn=set_client_for_session, inputs=[model_dropdown], outputs=[client])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
+
# Initialize client on page load
|
| 65 |
+
demo.load(fn=set_client_for_session, inputs=[gr.State("SmolVLM-Instruct")], outputs=[client])
|
| 66 |
|
| 67 |
+
if __name__ == "__main__":
|
| 68 |
+
demo.launch()
|
app_lumaai.py
CHANGED
|
@@ -2,6 +2,6 @@ import gradio as gr
|
|
| 2 |
import lumaai_gradio
|
| 3 |
|
| 4 |
demo = gr.load(
|
| 5 |
-
name=
|
| 6 |
src=lumaai_gradio.registry,
|
| 7 |
-
)
|
|
|
|
| 2 |
import lumaai_gradio
|
| 3 |
|
| 4 |
demo = gr.load(
|
| 5 |
+
name="dream-machine",
|
| 6 |
src=lumaai_gradio.registry,
|
| 7 |
+
)
|
app_meta.py
CHANGED
|
@@ -2,4 +2,4 @@ import gradio as gr
|
|
| 2 |
|
| 3 |
demo = gr.load("models/meta-llama/Llama-3.3-70B-Instruct")
|
| 4 |
|
| 5 |
-
demo = demo
|
|
|
|
| 2 |
|
| 3 |
demo = gr.load("models/meta-llama/Llama-3.3-70B-Instruct")
|
| 4 |
|
| 5 |
+
demo = demo
|
app_mindsearch.py
CHANGED
|
@@ -4,9 +4,9 @@ import gradio as gr
|
|
| 4 |
demo = gr.load(name="internlm/MindSearch", src="spaces")
|
| 5 |
|
| 6 |
# Disable API access for all functions
|
| 7 |
-
if hasattr(demo,
|
| 8 |
for fn in demo.fns.values():
|
| 9 |
fn.api_name = False
|
| 10 |
|
| 11 |
if __name__ == "__main__":
|
| 12 |
-
demo.launch()
|
|
|
|
| 4 |
demo = gr.load(name="internlm/MindSearch", src="spaces")
|
| 5 |
|
| 6 |
# Disable API access for all functions
|
| 7 |
+
if hasattr(demo, "fns"):
|
| 8 |
for fn in demo.fns.values():
|
| 9 |
fn.api_name = False
|
| 10 |
|
| 11 |
if __name__ == "__main__":
|
| 12 |
+
demo.launch()
|
app_paligemma.py
CHANGED
|
@@ -1,17 +1,15 @@
|
|
| 1 |
-
from gradio_client import Client, handle_file
|
| 2 |
import gradio as gr
|
| 3 |
-
import
|
|
|
|
|
|
|
| 4 |
|
| 5 |
-
MODELS = {
|
| 6 |
-
"Paligemma-10B": "akhaliq/paligemma2-10b-ft-docci-448"
|
| 7 |
-
}
|
| 8 |
|
| 9 |
def create_chat_fn(client, system_prompt, temperature, max_tokens, top_k, rep_penalty, top_p):
|
| 10 |
def chat(message, history):
|
| 11 |
text = message.get("text", "")
|
| 12 |
files = message.get("files", [])
|
| 13 |
processed_files = [handle_file(f) for f in files]
|
| 14 |
-
|
| 15 |
response = client.predict(
|
| 16 |
message={"text": text, "files": processed_files},
|
| 17 |
system_prompt=system_prompt,
|
|
@@ -20,79 +18,61 @@ def create_chat_fn(client, system_prompt, temperature, max_tokens, top_k, rep_pe
|
|
| 20 |
top_k=top_k,
|
| 21 |
repetition_penalty=rep_penalty,
|
| 22 |
top_p=top_p,
|
| 23 |
-
api_name="/chat"
|
| 24 |
)
|
| 25 |
return response
|
|
|
|
| 26 |
return chat
|
| 27 |
|
|
|
|
| 28 |
def set_client_for_session(model_name, request: gr.Request):
|
| 29 |
headers = {}
|
| 30 |
-
if request and hasattr(request,
|
| 31 |
-
x_ip_token = request.headers.get(
|
| 32 |
if x_ip_token:
|
| 33 |
headers["X-IP-Token"] = x_ip_token
|
| 34 |
-
|
| 35 |
return Client(MODELS[model_name], headers=headers)
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|
| 39 |
if client is None:
|
| 40 |
return "Error: Client not initialized. Please refresh the page."
|
| 41 |
try:
|
| 42 |
-
return create_chat_fn(client, system_prompt, temperature,
|
| 43 |
-
|
|
|
|
| 44 |
except Exception as e:
|
| 45 |
print(f"Error during chat: {str(e)}")
|
| 46 |
return f"Error during chat: {str(e)}"
|
| 47 |
|
|
|
|
| 48 |
with gr.Blocks() as demo:
|
| 49 |
client = gr.State()
|
| 50 |
-
|
| 51 |
with gr.Accordion("Advanced Settings", open=False):
|
| 52 |
-
system_prompt = gr.Textbox(
|
| 53 |
-
value="You are a helpful AI assistant.",
|
| 54 |
-
label="System Prompt"
|
| 55 |
-
)
|
| 56 |
with gr.Row():
|
| 57 |
-
temperature = gr.Slider(
|
| 58 |
-
|
| 59 |
-
label="Temperature"
|
| 60 |
-
)
|
| 61 |
-
top_p = gr.Slider(
|
| 62 |
-
minimum=0.0, maximum=1.0, value=0.95,
|
| 63 |
-
label="Top P"
|
| 64 |
-
)
|
| 65 |
with gr.Row():
|
| 66 |
-
top_k = gr.Slider(
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
rep_penalty = gr.Slider(
|
| 71 |
-
minimum=1.0, maximum=2.0, value=1.1,
|
| 72 |
-
label="Repetition Penalty"
|
| 73 |
-
)
|
| 74 |
-
max_tokens = gr.Slider(
|
| 75 |
-
minimum=64, maximum=4096, value=1024, step=64,
|
| 76 |
-
label="Max Tokens"
|
| 77 |
-
)
|
| 78 |
-
|
| 79 |
chat_interface = gr.ChatInterface(
|
| 80 |
fn=safe_chat_fn,
|
| 81 |
-
additional_inputs=[client, system_prompt, temperature,
|
| 82 |
-
|
| 83 |
-
multimodal=True
|
| 84 |
)
|
| 85 |
-
|
| 86 |
# Initialize client on page load with default model
|
| 87 |
-
demo.load(
|
| 88 |
-
fn=set_client_for_session,
|
| 89 |
-
inputs=[gr.State("Paligemma-10B")], # Using default model
|
| 90 |
-
outputs=[client]
|
| 91 |
-
)
|
| 92 |
|
| 93 |
# Move the API access check here, after demo is defined
|
| 94 |
-
if hasattr(demo,
|
| 95 |
for fn in demo.fns.values():
|
| 96 |
fn.api_name = False
|
| 97 |
|
| 98 |
-
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
+
from gradio_client import Client, handle_file
|
| 3 |
+
|
| 4 |
+
MODELS = {"Paligemma-10B": "akhaliq/paligemma2-10b-ft-docci-448"}
|
| 5 |
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
def create_chat_fn(client, system_prompt, temperature, max_tokens, top_k, rep_penalty, top_p):
|
| 8 |
def chat(message, history):
|
| 9 |
text = message.get("text", "")
|
| 10 |
files = message.get("files", [])
|
| 11 |
processed_files = [handle_file(f) for f in files]
|
| 12 |
+
|
| 13 |
response = client.predict(
|
| 14 |
message={"text": text, "files": processed_files},
|
| 15 |
system_prompt=system_prompt,
|
|
|
|
| 18 |
top_k=top_k,
|
| 19 |
repetition_penalty=rep_penalty,
|
| 20 |
top_p=top_p,
|
| 21 |
+
api_name="/chat",
|
| 22 |
)
|
| 23 |
return response
|
| 24 |
+
|
| 25 |
return chat
|
| 26 |
|
| 27 |
+
|
| 28 |
def set_client_for_session(model_name, request: gr.Request):
|
| 29 |
headers = {}
|
| 30 |
+
if request and hasattr(request, "headers"):
|
| 31 |
+
x_ip_token = request.headers.get("x-ip-token")
|
| 32 |
if x_ip_token:
|
| 33 |
headers["X-IP-Token"] = x_ip_token
|
| 34 |
+
|
| 35 |
return Client(MODELS[model_name], headers=headers)
|
| 36 |
|
| 37 |
+
|
| 38 |
+
def safe_chat_fn(message, history, client, system_prompt, temperature, max_tokens, top_k, rep_penalty, top_p):
|
| 39 |
if client is None:
|
| 40 |
return "Error: Client not initialized. Please refresh the page."
|
| 41 |
try:
|
| 42 |
+
return create_chat_fn(client, system_prompt, temperature, max_tokens, top_k, rep_penalty, top_p)(
|
| 43 |
+
message, history
|
| 44 |
+
)
|
| 45 |
except Exception as e:
|
| 46 |
print(f"Error during chat: {str(e)}")
|
| 47 |
return f"Error during chat: {str(e)}"
|
| 48 |
|
| 49 |
+
|
| 50 |
with gr.Blocks() as demo:
|
| 51 |
client = gr.State()
|
| 52 |
+
|
| 53 |
with gr.Accordion("Advanced Settings", open=False):
|
| 54 |
+
system_prompt = gr.Textbox(value="You are a helpful AI assistant.", label="System Prompt")
|
|
|
|
|
|
|
|
|
|
| 55 |
with gr.Row():
|
| 56 |
+
temperature = gr.Slider(minimum=0.0, maximum=2.0, value=0.7, label="Temperature")
|
| 57 |
+
top_p = gr.Slider(minimum=0.0, maximum=1.0, value=0.95, label="Top P")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
with gr.Row():
|
| 59 |
+
top_k = gr.Slider(minimum=1, maximum=100, value=40, step=1, label="Top K")
|
| 60 |
+
rep_penalty = gr.Slider(minimum=1.0, maximum=2.0, value=1.1, label="Repetition Penalty")
|
| 61 |
+
max_tokens = gr.Slider(minimum=64, maximum=4096, value=1024, step=64, label="Max Tokens")
|
| 62 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
chat_interface = gr.ChatInterface(
|
| 64 |
fn=safe_chat_fn,
|
| 65 |
+
additional_inputs=[client, system_prompt, temperature, max_tokens, top_k, rep_penalty, top_p],
|
| 66 |
+
multimodal=True,
|
|
|
|
| 67 |
)
|
| 68 |
+
|
| 69 |
# Initialize client on page load with default model
|
| 70 |
+
demo.load(fn=set_client_for_session, inputs=[gr.State("Paligemma-10B")], outputs=[client]) # Using default model
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
# Move the API access check here, after demo is defined
|
| 73 |
+
if hasattr(demo, "fns"):
|
| 74 |
for fn in demo.fns.values():
|
| 75 |
fn.api_name = False
|
| 76 |
|
| 77 |
+
if __name__ == "__main__":
|
| 78 |
+
demo.launch()
|
app_playai.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import playai_gradio
|
| 3 |
|
| 4 |
-
demo =gr.load(
|
| 5 |
-
name=
|
| 6 |
src=playai_gradio.registry,
|
| 7 |
)
|
| 8 |
|
| 9 |
for fn in demo.fns.values():
|
| 10 |
-
fn.api_name = False
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import playai_gradio
|
| 3 |
|
| 4 |
+
demo = gr.load(
|
| 5 |
+
name="PlayDialog",
|
| 6 |
src=playai_gradio.registry,
|
| 7 |
)
|
| 8 |
|
| 9 |
for fn in demo.fns.values():
|
| 10 |
+
fn.api_name = False
|
app_showui.py
CHANGED
|
@@ -5,6 +5,6 @@ demo = gr.load(name="showlab/ShowUI", src="spaces")
|
|
| 5 |
|
| 6 |
|
| 7 |
# Disable API access for all functions
|
| 8 |
-
if hasattr(demo,
|
| 9 |
for fn in demo.fns.values():
|
| 10 |
fn.api_name = False
|
|
|
|
| 5 |
|
| 6 |
|
| 7 |
# Disable API access for all functions
|
| 8 |
+
if hasattr(demo, "fns"):
|
| 9 |
for fn in demo.fns.values():
|
| 10 |
fn.api_name = False
|
app_trellis.py
CHANGED
|
@@ -7,4 +7,4 @@ demo = gr.load(name="JeffreyXiang/TRELLIS", src="spaces")
|
|
| 7 |
# Disable API access for all functions
|
| 8 |
if hasattr(demo, "fns"):
|
| 9 |
for fn in demo.fns.values():
|
| 10 |
-
fn.api_name = False
|
|
|
|
| 7 |
# Disable API access for all functions
|
| 8 |
if hasattr(demo, "fns"):
|
| 9 |
for fn in demo.fns.values():
|
| 10 |
+
fn.api_name = False
|
utils.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from typing import Callable,
|
| 2 |
|
| 3 |
import gradio as gr
|
| 4 |
|
|
|
|
| 1 |
+
from typing import Callable, Dict, Literal, Union
|
| 2 |
|
| 3 |
import gradio as gr
|
| 4 |
|