Spaces:
Runtime error
Runtime error
chore: update the layout
Browse files- .gradio/certificate.pem +31 -0
- .idea/.gitignore +8 -0
- .idea/inspectionProfiles/Project_Default.xml +14 -0
- .idea/inspectionProfiles/profiles_settings.xml +6 -0
- .idea/llama-3.2-3b-voice.iml +14 -0
- .idea/misc.xml +8 -0
- .idea/modules.xml +8 -0
- .idea/vcs.xml +6 -0
- __pycache__/app.cpython-310.pyc +0 -0
- app.py +53 -40
.gradio/certificate.pem
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
-----BEGIN CERTIFICATE-----
|
2 |
+
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
|
31 |
+
-----END CERTIFICATE-----
|
.idea/.gitignore
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Default ignored files
|
2 |
+
/shelf/
|
3 |
+
/workspace.xml
|
4 |
+
# Editor-based HTTP Client requests
|
5 |
+
/httpRequests/
|
6 |
+
# Datasource local storage ignored files
|
7 |
+
/dataSources/
|
8 |
+
/dataSources.local.xml
|
.idea/inspectionProfiles/Project_Default.xml
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<component name="InspectionProjectProfileManager">
|
2 |
+
<profile version="1.0">
|
3 |
+
<option name="myName" value="Project Default" />
|
4 |
+
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
5 |
+
<option name="ignoredPackages">
|
6 |
+
<value>
|
7 |
+
<list size="1">
|
8 |
+
<item index="0" class="java.lang.String" itemvalue="flash_attn" />
|
9 |
+
</list>
|
10 |
+
</value>
|
11 |
+
</option>
|
12 |
+
</inspection_tool>
|
13 |
+
</profile>
|
14 |
+
</component>
|
.idea/inspectionProfiles/profiles_settings.xml
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<component name="InspectionProjectProfileManager">
|
2 |
+
<settings>
|
3 |
+
<option name="USE_PROJECT_PROFILE" value="false" />
|
4 |
+
<version value="1.0" />
|
5 |
+
</settings>
|
6 |
+
</component>
|
.idea/llama-3.2-3b-voice.iml
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<module type="PYTHON_MODULE" version="4">
|
3 |
+
<component name="NewModuleRootManager">
|
4 |
+
<content url="file://$MODULE_DIR$">
|
5 |
+
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
6 |
+
</content>
|
7 |
+
<orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
|
8 |
+
<orderEntry type="sourceFolder" forTests="false" />
|
9 |
+
</component>
|
10 |
+
<component name="PyDocumentationSettings">
|
11 |
+
<option name="format" value="PLAIN" />
|
12 |
+
<option name="myDocStringFormat" value="Plain" />
|
13 |
+
</component>
|
14 |
+
</module>
|
.idea/misc.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="Black">
|
4 |
+
<option name="enabledOnSave" value="true" />
|
5 |
+
<option name="sdkName" value="Python 3.9" />
|
6 |
+
</component>
|
7 |
+
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
8 |
+
</project>
|
.idea/modules.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="ProjectModuleManager">
|
4 |
+
<modules>
|
5 |
+
<module fileurl="file://$PROJECT_DIR$/.idea/llama-3.2-3b-voice.iml" filepath="$PROJECT_DIR$/.idea/llama-3.2-3b-voice.iml" />
|
6 |
+
</modules>
|
7 |
+
</component>
|
8 |
+
</project>
|
.idea/vcs.xml
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="VcsDirectoryMappings">
|
4 |
+
<mapping directory="" vcs="Git" />
|
5 |
+
</component>
|
6 |
+
</project>
|
__pycache__/app.cpython-310.pyc
ADDED
Binary file (6.18 kB). View file
|
|
app.py
CHANGED
@@ -2,9 +2,7 @@ import gradio as gr
|
|
2 |
import numpy as np
|
3 |
import io
|
4 |
from pydub import AudioSegment
|
5 |
-
import tempfile
|
6 |
import openai
|
7 |
-
import time
|
8 |
from dataclasses import dataclass, field
|
9 |
from threading import Lock
|
10 |
import base64
|
@@ -20,15 +18,17 @@ class AppState:
|
|
20 |
output_format: str = "mp3"
|
21 |
stopped: bool = False
|
22 |
|
|
|
23 |
# Global lock for thread safety
|
24 |
state_lock = Lock()
|
25 |
|
|
|
26 |
def create_client(api_key):
|
27 |
return openai.OpenAI(
|
28 |
-
base_url="https://llama3-1-8b.lepton.run/api/v1/",
|
29 |
-
api_key=api_key
|
30 |
)
|
31 |
|
|
|
32 |
def determine_pause(audio, sampling_rate, state):
|
33 |
# Take the last 1 second of audio
|
34 |
pause_length = int(sampling_rate * 1) # 1 second
|
@@ -45,6 +45,7 @@ def determine_pause(audio, sampling_rate, state):
|
|
45 |
else:
|
46 |
return False
|
47 |
|
|
|
48 |
def process_audio(audio: tuple, state: AppState):
|
49 |
if state.stream is None:
|
50 |
state.stream = audio[1]
|
@@ -60,6 +61,7 @@ def process_audio(audio: tuple, state: AppState):
|
|
60 |
else:
|
61 |
return None, state
|
62 |
|
|
|
63 |
def generate_response_and_audio(audio_bytes: bytes, state: AppState):
|
64 |
if state.client is None:
|
65 |
raise gr.Error("Please enter a valid API key first.")
|
@@ -74,10 +76,12 @@ def generate_response_and_audio(audio_bytes: bytes, state: AppState):
|
|
74 |
"require_audio": True,
|
75 |
"tts_preset_id": "jessica",
|
76 |
"tts_audio_format": format_,
|
77 |
-
"tts_audio_bitrate": bitrate
|
78 |
},
|
79 |
model="llama3.1-8b",
|
80 |
-
messages=[
|
|
|
|
|
81 |
temperature=0.7,
|
82 |
max_tokens=256,
|
83 |
stream=True,
|
@@ -90,20 +94,21 @@ def generate_response_and_audio(audio_bytes: bytes, state: AppState):
|
|
90 |
if not chunk.choices:
|
91 |
continue
|
92 |
content = chunk.choices[0].delta.content
|
93 |
-
audio = getattr(chunk.choices[0],
|
94 |
if content:
|
95 |
full_response += content
|
96 |
yield full_response, None, state
|
97 |
if audio:
|
98 |
audios.extend(audio)
|
99 |
|
100 |
-
final_audio = b
|
101 |
|
102 |
yield full_response, final_audio, state
|
103 |
|
104 |
except Exception as e:
|
105 |
raise gr.Error(f"Error during audio streaming: {e}")
|
106 |
|
|
|
107 |
def response(state: AppState):
|
108 |
if state.stream is None or len(state.stream) == 0:
|
109 |
return None, None, state
|
@@ -139,43 +144,54 @@ def response(state: AppState):
|
|
139 |
|
140 |
return chatbot_output, final_audio, state
|
141 |
|
|
|
142 |
def start_recording_user(state: AppState):
|
143 |
if not state.stopped:
|
144 |
return gr.Audio(recording=True)
|
145 |
else:
|
146 |
return gr.Audio(recording=False)
|
147 |
|
|
|
148 |
def set_api_key(api_key, state):
|
149 |
if not api_key:
|
150 |
raise gr.Error("Please enter a valid API key.")
|
151 |
-
|
152 |
-
|
|
|
|
|
|
|
153 |
|
154 |
-
def update_format(format, state):
|
155 |
-
state.output_format = format
|
156 |
-
return state
|
157 |
|
158 |
with gr.Blocks() as demo:
|
|
|
|
|
|
|
|
|
159 |
with gr.Row():
|
160 |
-
|
161 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
with gr.Row():
|
169 |
-
with gr.Column():
|
170 |
-
input_audio = gr.Audio(label="Input Audio", sources="microphone", type="numpy")
|
171 |
-
with gr.Column():
|
172 |
-
chatbot = gr.Chatbot(label="Conversation", type="messages")
|
173 |
-
output_audio = gr.Audio(label="Output Audio", autoplay=True)
|
174 |
|
175 |
state = gr.State(AppState())
|
176 |
|
177 |
-
set_key_button.click(
|
178 |
-
|
|
|
|
|
|
|
179 |
|
180 |
stream = input_audio.stream(
|
181 |
process_audio,
|
@@ -186,23 +202,20 @@ with gr.Blocks() as demo:
|
|
186 |
)
|
187 |
|
188 |
respond = input_audio.stop_recording(
|
189 |
-
response,
|
190 |
-
[state],
|
191 |
-
[chatbot, output_audio, state]
|
192 |
)
|
193 |
# Update the chatbot with the final conversation
|
194 |
respond.then(lambda s: s.conversation, [state], [chatbot])
|
195 |
|
196 |
# Automatically restart recording after the assistant's response
|
197 |
-
restart = output_audio.stop(
|
198 |
-
start_recording_user,
|
199 |
-
[state],
|
200 |
-
[input_audio]
|
201 |
-
)
|
202 |
|
203 |
# Add a "Stop Conversation" button
|
204 |
-
cancel
|
205 |
-
|
206 |
-
|
|
|
|
|
|
|
207 |
|
208 |
-
demo.launch()
|
|
|
2 |
import numpy as np
|
3 |
import io
|
4 |
from pydub import AudioSegment
|
|
|
5 |
import openai
|
|
|
6 |
from dataclasses import dataclass, field
|
7 |
from threading import Lock
|
8 |
import base64
|
|
|
18 |
output_format: str = "mp3"
|
19 |
stopped: bool = False
|
20 |
|
21 |
+
|
22 |
# Global lock for thread safety
|
23 |
state_lock = Lock()
|
24 |
|
25 |
+
|
26 |
def create_client(api_key):
|
27 |
return openai.OpenAI(
|
28 |
+
base_url="https://llama3-1-8b.lepton.run/api/v1/", api_key=api_key
|
|
|
29 |
)
|
30 |
|
31 |
+
|
32 |
def determine_pause(audio, sampling_rate, state):
|
33 |
# Take the last 1 second of audio
|
34 |
pause_length = int(sampling_rate * 1) # 1 second
|
|
|
45 |
else:
|
46 |
return False
|
47 |
|
48 |
+
|
49 |
def process_audio(audio: tuple, state: AppState):
|
50 |
if state.stream is None:
|
51 |
state.stream = audio[1]
|
|
|
61 |
else:
|
62 |
return None, state
|
63 |
|
64 |
+
|
65 |
def generate_response_and_audio(audio_bytes: bytes, state: AppState):
|
66 |
if state.client is None:
|
67 |
raise gr.Error("Please enter a valid API key first.")
|
|
|
76 |
"require_audio": True,
|
77 |
"tts_preset_id": "jessica",
|
78 |
"tts_audio_format": format_,
|
79 |
+
"tts_audio_bitrate": bitrate,
|
80 |
},
|
81 |
model="llama3.1-8b",
|
82 |
+
messages=[
|
83 |
+
{"role": "user", "content": [{"type": "audio", "data": audio_data}]}
|
84 |
+
],
|
85 |
temperature=0.7,
|
86 |
max_tokens=256,
|
87 |
stream=True,
|
|
|
94 |
if not chunk.choices:
|
95 |
continue
|
96 |
content = chunk.choices[0].delta.content
|
97 |
+
audio = getattr(chunk.choices[0], "audio", [])
|
98 |
if content:
|
99 |
full_response += content
|
100 |
yield full_response, None, state
|
101 |
if audio:
|
102 |
audios.extend(audio)
|
103 |
|
104 |
+
final_audio = b"".join([base64.b64decode(a) for a in audios])
|
105 |
|
106 |
yield full_response, final_audio, state
|
107 |
|
108 |
except Exception as e:
|
109 |
raise gr.Error(f"Error during audio streaming: {e}")
|
110 |
|
111 |
+
|
112 |
def response(state: AppState):
|
113 |
if state.stream is None or len(state.stream) == 0:
|
114 |
return None, None, state
|
|
|
144 |
|
145 |
return chatbot_output, final_audio, state
|
146 |
|
147 |
+
|
148 |
def start_recording_user(state: AppState):
|
149 |
if not state.stopped:
|
150 |
return gr.Audio(recording=True)
|
151 |
else:
|
152 |
return gr.Audio(recording=False)
|
153 |
|
154 |
+
|
155 |
def set_api_key(api_key, state):
|
156 |
if not api_key:
|
157 |
raise gr.Error("Please enter a valid API key.")
|
158 |
+
try:
|
159 |
+
state.client = create_client(api_key)
|
160 |
+
return gr.update(value="API key set successfully!", visible=True), state
|
161 |
+
except Exception as e:
|
162 |
+
return gr.update(value="Connection error", visible=True), state
|
163 |
|
|
|
|
|
|
|
164 |
|
165 |
with gr.Blocks() as demo:
|
166 |
+
gr.Markdown("# Lepton LLM Voice Mode")
|
167 |
+
gr.Markdown(
|
168 |
+
"You can find Lepton serverless endpoint API Key at [here](https://dashboard.lepton.ai/workspace-redirect/settings/api-tokens)"
|
169 |
+
)
|
170 |
with gr.Row():
|
171 |
+
with gr.Column(scale=3):
|
172 |
+
api_key_input = gr.Textbox(
|
173 |
+
type="password", label="Enter your Lepton API Key"
|
174 |
+
)
|
175 |
+
with gr.Column(scale=1):
|
176 |
+
set_key_button = gr.Button("Set API Key", scale=2, variant="secondary")
|
177 |
+
|
178 |
+
api_key_status = gr.Textbox(
|
179 |
+
show_label=False, container=False, interactive=False, visible=False
|
180 |
+
)
|
181 |
|
182 |
+
with gr.Blocks():
|
183 |
+
input_audio = gr.Audio(label="Input Audio", sources="microphone", type="numpy")
|
184 |
+
output_audio = gr.Audio(label="Output Audio", autoplay=True)
|
185 |
+
chatbot = gr.Chatbot(label="Conversation", type="messages")
|
186 |
+
cancel = gr.Button("Stop Conversation", variant="stop")
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
|
188 |
state = gr.State(AppState())
|
189 |
|
190 |
+
set_key_button.click(
|
191 |
+
set_api_key,
|
192 |
+
inputs=[api_key_input, state],
|
193 |
+
outputs=[api_key_status, state],
|
194 |
+
)
|
195 |
|
196 |
stream = input_audio.stream(
|
197 |
process_audio,
|
|
|
202 |
)
|
203 |
|
204 |
respond = input_audio.stop_recording(
|
205 |
+
response, [state], [chatbot, output_audio, state]
|
|
|
|
|
206 |
)
|
207 |
# Update the chatbot with the final conversation
|
208 |
respond.then(lambda s: s.conversation, [state], [chatbot])
|
209 |
|
210 |
# Automatically restart recording after the assistant's response
|
211 |
+
restart = output_audio.stop(start_recording_user, [state], [input_audio])
|
|
|
|
|
|
|
|
|
212 |
|
213 |
# Add a "Stop Conversation" button
|
214 |
+
cancel.click(
|
215 |
+
lambda: (AppState(stopped=True), gr.Audio(recording=False)),
|
216 |
+
None,
|
217 |
+
[state, input_audio],
|
218 |
+
cancels=[respond, restart],
|
219 |
+
)
|
220 |
|
221 |
+
demo.launch(share=True)
|