forked from fishaudio/fish-speech
-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.py
111 lines (85 loc) · 2.78 KB
/
run.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import audioop
import base64
import numpy as np
import soundfile as sf
from fastapi import FastAPI, WebSocket
from fastapi.responses import Response
from loguru import logger
from stream_service import FishAgentPipeline
app = FastAPI()
@app.post("/incoming")
async def handle_incoming():
xml = """<Response>
<Connect>
<Stream url="wss://2427-24-4-31-213.ngrok-free.app/connection" />
</Connect>
</Response>"""
logger.info("Incoming call received")
return Response(media_type="text/xml", content=xml)
async def send_audio(ws, audio, stream_sid=""):
await ws.send_json(
{
"streamSid": stream_sid,
"event": "media",
"media": {
"payload": audio,
},
}
)
def decode_mu_law(data):
samples = audioop.ulaw2lin(data, 2)
samples = np.frombuffer(samples, dtype=np.int16)
samples = samples.astype(np.float32) / 32768.0
return samples
def encode_mu_law(data):
samples = np.clip(data, -1.0, 1.0)
samples = (samples * 32768).astype(np.int16)
samples = audioop.lin2ulaw(samples.tobytes(), 2)
return samples
is_working = False
@app.websocket("/connection")
async def handle_connection(websocket: WebSocket):
global is_working
await websocket.accept()
logger.info("Connection established")
stream_sid = None
call_sid = None
if is_working:
logger.info("Already working, closing connection")
await websocket.close()
return
is_working = True
pipe.reset()
while True:
data = await websocket.receive_json()
if data["event"] == "connected":
logger.info("Connected message received")
elif data["event"] == "start":
stream_sid = data["start"]["streamSid"]
call_sid = data["start"]["callSid"]
logger.info(f"Start media streaming: {stream_sid} - {call_sid}")
elif data["event"] == "media":
payload = data["media"]["payload"]
chunk = base64.b64decode(payload)
samples = decode_mu_law(chunk)
for i in pipe.add_chunk(samples, sr=8000):
await send_audio(
websocket, base64.b64encode(encode_mu_law(i)).decode(), stream_sid
)
elif data["event"] == "closed":
logger.info("Connection closed")
await websocket.close()
break
elif data["event"] == "stop":
logger.info("Stop media streaming")
await websocket.close()
break
else:
logger.info(f"Unknown event: {data}")
is_working = False
if __name__ == "__main__":
import uvicorn
pipe = FishAgentPipeline()
pipe.warmup()
logger.info("Starting server")
uvicorn.run(app, host="localhost", port=5000)