whispering/whispering/websocket_client.py

109 lines
3 KiB
Python
Raw Normal View History

2022-09-24 11:46:10 +00:00
#!/usr/bin/env python3
import asyncio
2022-10-02 13:08:22 +00:00
import json
import sys
2022-09-24 19:13:28 +00:00
from logging import getLogger
2022-10-03 13:38:35 +00:00
from pathlib import Path
2022-09-24 11:46:10 +00:00
from typing import Optional, Union
import sounddevice as sd
import websockets
from whisper.audio import N_FRAMES, SAMPLE_RATE
2022-10-03 13:38:35 +00:00
from whispering.schema import ParsedChunk, StdoutWriter
2022-10-02 12:59:02 +00:00
from whispering.transcriber import Context
2022-09-24 11:46:10 +00:00
logger = getLogger(__name__)
def sd_callback(indata, frames, time, status):
if status:
logger.warning(status)
loop.call_soon_threadsafe(q.put_nowait, indata.ravel().tobytes())
async def transcribe_from_mic_and_send(
*,
sd_device: Optional[Union[int, str]],
num_block: int,
host: str,
port: int,
2022-10-02 12:59:02 +00:00
ctx: Context,
2022-10-03 13:38:35 +00:00
path_out: Union[Path, StdoutWriter],
2022-09-24 11:46:10 +00:00
) -> None:
uri = f"ws://{host}:{port}"
with sd.InputStream(
samplerate=SAMPLE_RATE,
blocksize=N_FRAMES * num_block,
device=sd_device,
dtype="float32",
channels=1,
callback=sd_callback,
2022-10-03 13:38:35 +00:00
), path_out.open("w") as outf:
2022-09-24 11:46:10 +00:00
async with websockets.connect(uri, max_size=999999999) as ws: # type:ignore
2022-10-02 13:02:17 +00:00
logger.debug("Sent context")
2022-10-02 13:15:45 +00:00
v: str = ctx.json()
await ws.send("""{"context": """ + v + """}""")
2022-10-02 13:02:17 +00:00
2022-09-24 11:46:10 +00:00
idx: int = 0
while True:
async def g():
return await q.get()
2022-09-24 12:50:04 +00:00
logger.debug(f"Loop #: {idx}")
segment = None
2022-09-24 11:46:10 +00:00
try:
2022-09-24 12:50:04 +00:00
segment = await asyncio.wait_for(g(), timeout=0.5)
2022-09-24 11:46:10 +00:00
except asyncio.TimeoutError:
2022-09-24 12:50:04 +00:00
pass
if segment is not None:
logger.debug(f"Segment size: {len(segment)}")
await ws.send(segment)
logger.debug("Sent")
2022-09-24 11:46:10 +00:00
2022-09-24 12:50:04 +00:00
async def recv():
return await ws.recv()
2022-09-24 11:46:10 +00:00
2022-09-24 12:39:22 +00:00
while True:
2022-09-24 12:50:04 +00:00
try:
c = await asyncio.wait_for(recv(), timeout=0.5)
2022-10-02 13:08:22 +00:00
c_json = json.loads(c)
if (err := c_json.get("error")) is not None:
2022-10-03 13:38:35 +00:00
sys.stderr.write(f"Error: {err}\n")
2022-10-02 13:08:22 +00:00
sys.exit(1)
chunk = ParsedChunk.parse_obj(c_json)
2022-10-03 13:38:35 +00:00
outf.write(
f"{chunk.start:.2f}->{chunk.end:.2f}\t{chunk.text}\n"
)
outf.flush()
2022-09-24 12:50:04 +00:00
except asyncio.TimeoutError:
2022-09-24 12:39:22 +00:00
break
2022-09-24 11:46:10 +00:00
idx += 1
2022-10-02 12:59:02 +00:00
async def run_websocket_client(
*,
sd_device: Optional[Union[int, str]],
num_block: int,
host: str,
port: int,
ctx: Context,
no_progress: bool,
2022-10-03 13:38:35 +00:00
path_out: Union[Path, StdoutWriter],
2022-10-02 12:59:02 +00:00
) -> None:
2022-09-24 11:46:10 +00:00
global q
global loop
loop = asyncio.get_running_loop()
q = asyncio.Queue()
await transcribe_from_mic_and_send(
2022-10-02 12:59:02 +00:00
sd_device=sd_device,
num_block=num_block,
host=host,
port=port,
ctx=ctx,
2022-10-03 13:38:35 +00:00
path_out=path_out,
2022-09-24 11:46:10 +00:00
)