diff --git a/.gitignore b/.gitignore index 44773f4..cd3f4ed 100644 --- a/.gitignore +++ b/.gitignore @@ -167,4 +167,4 @@ cython_debug/ # ignore the aifs index files _.aifs -01OS/output_audio.wav \ No newline at end of file +01OS/output_audio.wav diff --git a/01OS/.env.example b/01OS/.env.example index fa20ac9..85bd2c6 100644 --- a/01OS/.env.example +++ b/01OS/.env.example @@ -36,6 +36,17 @@ STT_RUNNER=client # If server, audio will be sent over websocket. # Will expose the server publically and display that URL. SERVER_EXPOSE_PUBLICALLY=False +# Image capture settings +CAMERA_ENABLED=True + +# Camera device selection (Typically 0 for built-in, 1 for USB) +CAMERA_DEVICE_INDEX=0 + +# Camera warmup time +# This is a workaround for some cameras that don't immediately +# return a properly exposed picture when they are first turned on +CAMERA_WARMUP_SECONDS=0.4 + # Debug level # LOG_LEVEL=DEBUG LOG_LEVEL="INFO" \ No newline at end of file diff --git a/01OS/01OS/clients/base_device.py b/01OS/01OS/clients/base_device.py index 1855253..a8e75d9 100644 --- a/01OS/01OS/clients/base_device.py +++ b/01OS/01OS/clients/base_device.py @@ -1,6 +1,7 @@ from dotenv import load_dotenv load_dotenv() # take environment variables from .env. +import os import asyncio import threading import os @@ -21,7 +22,10 @@ import time import wave import tempfile from datetime import datetime +import cv2 +import base64 from interpreter import interpreter # Just for code execution. Maybe we should let people do from interpreter.computer import run? +# In the future, I guess kernel watching code should be elsewhere? Somewhere server / client agnostic? from ..server.utils.kernel import put_kernel_messages_into_queue from ..server.utils.get_system_info import get_system_info from ..server.stt.stt import stt_wav @@ -30,6 +34,11 @@ from ..server.utils.logs import setup_logging from ..server.utils.logs import logger setup_logging() + +from ..utils.accumulator import Accumulator + +accumulator = Accumulator() + # Configuration for Audio Recording CHUNK = 1024 # Record in chunks of 1024 samples FORMAT = pyaudio.paInt16 # 16 bits per sample @@ -38,25 +47,99 @@ RATE = 44100 # Sample rate RECORDING = False # Flag to control recording state SPACEBAR_PRESSED = False # Flag to track spacebar press state +# Camera configuration +CAMERA_ENABLED = bool(os.getenv('CAMERA_ENABLED', False)) +CAMERA_DEVICE_INDEX = int(os.getenv('CAMERA_DEVICE_INDEX', 0)) +CAMERA_WARMUP_SECONDS = float(os.getenv('CAMERA_WARMUP_SECONDS', 0)) + # Specify OS current_platform = get_system_info() # Initialize PyAudio p = pyaudio.PyAudio() -import asyncio - send_queue = queue.Queue() class Device: def __init__(self): self.pressed_keys = set() + self.captured_images = [] + self.audiosegments = [] + + def fetch_image_from_camera(self, camera_index=CAMERA_DEVICE_INDEX): + """Captures an image from the specified camera device and saves it to a temporary file. Adds the image to the captured_images list.""" + image_path = None + + cap = cv2.VideoCapture(camera_index) + ret, frame = cap.read() # Capture a single frame to initialize the camera + + if CAMERA_WARMUP_SECONDS > 0: + # Allow camera to warm up, then snap a picture again + # This is a workaround for some cameras that don't return a properly exposed + # picture immediately when they are first turned on + time.sleep(CAMERA_WARMUP_SECONDS) + ret, frame = cap.read() + + if ret: + temp_dir = tempfile.gettempdir() + image_path = os.path.join(temp_dir, f"01_photo_{datetime.now().strftime('%Y%m%d%H%M%S%f')}.png") + self.captured_images.append(image_path) + cv2.imwrite(image_path, frame) + logger.info(f"Camera image captured to {image_path}") + logger.info(f"You now have {len(self.captured_images)} images which will be sent along with your next audio message.") + else: + logger.error(f"Error: Couldn't capture an image from camera ({camera_index})") + + cap.release() + + return image_path + + + def encode_image_to_base64(self, image_path): + """Encodes an image file to a base64 string.""" + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()).decode('utf-8') + + def add_image_to_send_queue(self, image_path): + """Encodes an image and adds an LMC message to the send queue with the image data.""" + base64_image = self.encode_image_to_base64(image_path) + image_message = { + "role": "user", + "type": "image", + "format": "base64.png", + "content": base64_image + } + send_queue.put(image_message) + # Delete the image file from the file system after sending it + os.remove(image_path) + + def queue_all_captured_images(self): + """Queues all captured images to be sent.""" + for image_path in self.captured_images: + self.add_image_to_send_queue(image_path) + self.captured_images.clear() # Clear the list after sending + + + async def play_audiosegments(self): + """Plays them sequentially.""" + while True: + try: + for audio in self.audiosegments: + play(audio) + self.audiosegments.remove(audio) + await asyncio.sleep(0.1) + except asyncio.exceptions.CancelledError: + # This happens once at the start? + pass + except: + logger.info(traceback.format_exc()) + def record_audio(self): if os.getenv('STT_RUNNER') == "server": # STT will happen on the server. we're sending audio. - send_queue.put({"role": "user", "type": "audio", "format": "audio/wav", "start": True}) + send_queue.put({"role": "user", "type": "audio", "format": "bytes.wav", "start": True}) elif os.getenv('STT_RUNNER') == "client": # STT will happen here, on the client. we're sending text. send_queue.put({"role": "user", "type": "message", "start": True}) @@ -92,9 +175,11 @@ class Device: send_queue.put({"role": "user", "type": "message", "content": "stop"}) send_queue.put({"role": "user", "type": "message", "end": True}) else: - send_queue.put({"role": "user", "type": "audio", "format": "audio/wav", "content": ""}) - send_queue.put({"role": "user", "type": "audio", "format": "audio/wav", "end": True}) + send_queue.put({"role": "user", "type": "audio", "format": "bytes.wav", "content": ""}) + send_queue.put({"role": "user", "type": "audio", "format": "bytes.wav", "end": True}) else: + self.queue_all_captured_images() + if os.getenv('STT_RUNNER') == "client": # Run stt then send text text = stt_wav(wav_path) @@ -105,9 +190,9 @@ class Device: with open(wav_path, 'rb') as audio_file: byte_data = audio_file.read(CHUNK) while byte_data: - send_queue.put({"role": "user", "type": "audio", "format": "audio/wav", "content": str(byte_data)}) + send_queue.put(byte_data) byte_data = audio_file.read(CHUNK) - send_queue.put({"role": "user", "type": "audio", "format": "audio/wav", "end": True}) + send_queue.put({"role": "user", "type": "audio", "format": "bytes.wav", "end": True}) if os.path.exists(wav_path): os.remove(wav_path) @@ -125,86 +210,82 @@ class Device: RECORDING = False def on_press(self, key): - """Detect spacebar press, ESC key press, and Ctrl+C combination.""" + """Detect spacebar press and Ctrl+C combination.""" self.pressed_keys.add(key) # Add the pressed key to the set - if keyboard.Key.esc in self.pressed_keys: - logger.info("Exiting...") - os._exit(0) - elif keyboard.Key.space in self.pressed_keys: + if keyboard.Key.space in self.pressed_keys: self.toggle_recording(True) elif {keyboard.Key.ctrl, keyboard.KeyCode.from_char('c')} <= self.pressed_keys: logger.info("Ctrl+C pressed. Exiting...") os._exit(0) def on_release(self, key): - """Detect spacebar release and ESC key press.""" + """Detect spacebar release and 'c' key press for camera, and handle key release.""" self.pressed_keys.discard(key) # Remove the released key from the key press tracking set + if key == keyboard.Key.space: self.toggle_recording(False) - elif key == keyboard.Key.esc or (key == keyboard.Key.ctrl and keyboard.Key.c): - logger.info("Exiting...") - os._exit(0) + elif CAMERA_ENABLED and key == keyboard.KeyCode.from_char('c'): + self.fetch_image_from_camera() + async def message_sender(self, websocket): while True: message = await asyncio.get_event_loop().run_in_executor(None, send_queue.get) - await websocket.send(json.dumps(message)) + if isinstance(message, bytes): + await websocket.send(message) + else: + await websocket.send(json.dumps(message)) send_queue.task_done() + await asyncio.sleep(0.01) async def websocket_communication(self, WS_URL): while True: try: async with websockets.connect(WS_URL) as websocket: - logger.info("Press the spacebar to start/stop recording. Press ESC to exit.") + if CAMERA_ENABLED: + logger.info("Press the spacebar to start/stop recording. Press 'c' to capture an image from the camera. Press CTRL-C to exit.") + else: + logger.info("Press the spacebar to start/stop recording. Press CTRL-C to exit.") + asyncio.create_task(self.message_sender(websocket)) - initial_message = {"role": None, "type": None, "format": None, "content": None} - message_so_far = initial_message - while True: - message = await websocket.recv() + await asyncio.sleep(0.01) + chunk = await websocket.recv() - logger.debug(f"Got this message from the server: {type(message)} {message}") + logger.debug(f"Got this message from the server: {type(chunk)} {chunk}") - if type(message) == str: - message = json.loads(message) + if type(chunk) == str: + chunk = json.loads(chunk) - if message.get("end"): - logger.debug(f"Complete message from the server: {message_so_far}") - logger.info("\n") - message_so_far = initial_message + message = accumulator.accumulate(chunk) + if message == None: + # Will be None until we have a full message ready + continue - if "content" in message: - print(message['content'], end="", flush=True) - if any(message_so_far[key] != message[key] for key in message_so_far if key != "content"): - message_so_far = message - else: - message_so_far["content"] += message["content"] + # At this point, we have our message - if message["type"] == "audio" and "content" in message: - audio_bytes = bytes(ast.literal_eval(message["content"])) + if message["type"] == "audio" and message["format"].startswith("bytes"): # Convert bytes to audio file - audio_file = io.BytesIO(audio_bytes) - audio = AudioSegment.from_mp3(audio_file) - - # Play the audio - play(audio) + # Format will be bytes.wav or bytes.opus + audio_bytes = io.BytesIO(message["content"]) + audio = AudioSegment.from_file(audio_bytes, codec=message["format"].split(".")[1]) - await asyncio.sleep(1) + self.audiosegments.append(audio) # Run the code if that's the client's job if os.getenv('CODE_RUNNER') == "client": if message["type"] == "code" and "end" in message: - language = message_so_far["format"] - code = message_so_far["content"] + language = message["format"] + code = message["content"] result = interpreter.computer.run(language, code) send_queue.put(result) except: - # traceback.print_exc() + logger.debug(traceback.format_exc()) logger.info(f"Connecting to `{WS_URL}`...") await asyncio.sleep(2) @@ -221,6 +302,7 @@ class Device: if os.getenv('CODE_RUNNER') == "client": asyncio.create_task(put_kernel_messages_into_queue(send_queue)) + asyncio.create_task(self.play_audiosegments()) # If Raspberry Pi, add the button listener, otherwise use the spacebar if current_platform.startswith("raspberry-pi"): diff --git a/01OS/01OS/clients/start.sh b/01OS/01OS/clients/start.sh index 844e6a0..d602a78 100644 --- a/01OS/01OS/clients/start.sh +++ b/01OS/01OS/clients/start.sh @@ -1,8 +1,6 @@ DEVICE=$(uname -n) if [[ "$DEVICE" == "rpi" ]]; then - cd 01OS python -m 01OS.clients.rpi.device else - cd 01OS python -m 01OS.clients.macos.device fi diff --git a/01OS/01OS/server/server.py b/01OS/01OS/server/server.py index 3f38ab5..0902a63 100644 --- a/01OS/01OS/server/server.py +++ b/01OS/01OS/server/server.py @@ -11,7 +11,7 @@ from fastapi import FastAPI from fastapi.responses import PlainTextResponse from starlette.websockets import WebSocket, WebSocketDisconnect from .stt.stt import stt_bytes -from .tts.tts import tts +from .tts.tts import stream_tts from pathlib import Path import asyncio import urllib.parse @@ -19,11 +19,13 @@ from .utils.kernel import put_kernel_messages_into_queue from .i import configure_interpreter from interpreter import interpreter import ngrok +from ..utils.accumulator import Accumulator from .utils.logs import setup_logging from .utils.logs import logger setup_logging() +accumulator = Accumulator() app = FastAPI() @@ -102,59 +104,94 @@ async def websocket_endpoint(websocket: WebSocket): except WebSocketDisconnect: pass except Exception as e: - traceback.print_exc() + logger.debug(traceback.format_exc()) logger.info(f"Connection lost. Error: {e}") async def receive_messages(websocket: WebSocket): while True: - data = await websocket.receive_json() - if data["role"] == "computer": - from_computer.put(data) # To be handled by interpreter.computer.run - elif data["role"] == "user": - await from_user.put(data) - else: - raise("Unknown role:", data) + try: + try: + data = await websocket.receive() + except Exception as e: + print(str(e)) + return + if 'text' in data: + try: + data = json.loads(data['text']) + if data["role"] == "computer": + from_computer.put(data) # To be handled by interpreter.computer.run + elif data["role"] == "user": + await from_user.put(data) + else: + raise("Unknown role:", data) + except json.JSONDecodeError: + pass # data is not JSON, leave it as is + elif 'bytes' in data: + data = data['bytes'] # binary data + await from_user.put(data) + except WebSocketDisconnect as e: + if e.code == 1000: + logger.info("Websocket connection closed normally.") + return + else: + raise + async def send_messages(websocket: WebSocket): while True: message = await to_device.get() logger.debug(f"Sending to the device: {type(message)} {message}") - await websocket.send_json(message) + + try: + if isinstance(message, dict): + await websocket.send_json(message) + elif isinstance(message, bytes): + await websocket.send_bytes(message) + else: + raise TypeError("Message must be a dict or bytes") + except: + # Make sure to put the message back in the queue if you failed to send it + await to_device.put(message) + raise async def listener(): - audio_bytes = bytearray() + while True: while True: if not from_user.empty(): - message = await from_user.get() + chunk = await from_user.get() break elif not from_computer.empty(): - message = from_computer.get() + chunk = from_computer.get() break await asyncio.sleep(1) - if type(message) == str: - message = json.loads(message) + - # Hold the audio in a buffer. If it's ready (we got end flag, stt it) - if message["type"] == "audio": - if "content" in message: - audio_bytes.extend(bytes(ast.literal_eval(message["content"]))) - if "end" in message: - content = stt_bytes(audio_bytes, message["format"]) - if content == None: # If it was nothing / silence - continue - audio_bytes = bytearray() - message = {"role": "user", "type": "message", "content": content} - else: + message = accumulator.accumulate(chunk) + if message == None: + # Will be None until we have a full message ready + continue + + # print(str(message)[:1000]) + + # At this point, we have our message + + if message["type"] == "audio" and message["format"].startswith("bytes"): + + if not message["content"]: # If it was nothing / silence continue - # Ignore flags, we only needed them for audio ^ - if "content" not in message or message["content"] == None: - continue + # Convert bytes to audio file + # Format will be bytes.wav or bytes.opus + mime_type = "audio/" + message["format"].split(".")[1] + text = stt_bytes(message["content"], mime_type) + message = {"role": "user", "type": "message", "content": text} + + # At this point, we have only text messages # Custom stop message will halt us - if message["content"].lower().strip(".,!") == "stop": + if message["content"].lower().strip(".,! ") == "stop": continue # Load, append, and save conversation history @@ -175,19 +212,31 @@ async def listener(): # Yield to the event loop, so you actually send it out await asyncio.sleep(0.01) - # Speak full sentences out loud - if chunk["role"] == "assistant" and "content" in chunk: - accumulated_text += chunk["content"] - sentences = split_into_sentences(accumulated_text) - if is_full_sentence(sentences[-1]): - for sentence in sentences: - await stream_or_play_tts(sentence) - accumulated_text = "" - else: - for sentence in sentences[:-1]: - await stream_or_play_tts(sentence) - accumulated_text = sentences[-1] - + if os.getenv('TTS_RUNNER') == "server": + # Speak full sentences out loud + if chunk["role"] == "assistant" and "content" in chunk: + accumulated_text += chunk["content"] + sentences = split_into_sentences(accumulated_text) + + # If we're going to speak, say we're going to stop sending text. + # This should be fixed probably, we should be able to do both in parallel, or only one. + if any(is_full_sentence(sentence) for sentence in sentences): + await to_device.put({"role": "assistant", "type": "message", "end": True}) + + if is_full_sentence(sentences[-1]): + for sentence in sentences: + await stream_tts_to_device(sentence) + accumulated_text = "" + else: + for sentence in sentences[:-1]: + await stream_tts_to_device(sentence) + accumulated_text = sentences[-1] + + # If we're going to speak, say we're going to stop sending text. + # This should be fixed probably, we should be able to do both in parallel, or only one. + if any(is_full_sentence(sentence) for sentence in sentences): + await to_device.put({"role": "assistant", "type": "message", "start": True}) + # If we have a new message, save our progress and go back to the top if not from_user.empty(): @@ -217,19 +266,12 @@ async def listener(): break else: with open(conversation_history_path, 'w') as file: - json.dump(interpreter.messages, file, indent=4) - - -async def stream_or_play_tts(sentence): - - if os.getenv('TTS_RUNNER') == "server": - tts(sentence, play_audio=True) - else: - await to_device.put({"role": "assistant", "type": "audio", "format": "audio/mp3", "start": True}) - audio_bytes = tts(sentence, play_audio=False) - await to_device.put({"role": "assistant", "type": "audio", "format": "audio/mp3", "content": str(audio_bytes)}) - await to_device.put({"role": "assistant", "type": "audio", "format": "audio/mp3", "end": True}) + json.dump(interpreter.messages, file, indent=4) +async def stream_tts_to_device(sentence): + for chunk in stream_tts(sentence): + await to_device.put(chunk) + async def setup_ngrok(ngrok_auth_token, parsed_url): # Set up Ngrok logger.info("Setting up Ngrok") diff --git a/01OS/01OS/server/stt/local_service/__init__.py b/01OS/01OS/server/stt/local_service/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/01OS/01OS/server/stt/local_service/whisper-rust/.gitignore b/01OS/01OS/server/stt/local_service/whisper-rust/.gitignore deleted file mode 100644 index 71ab9a4..0000000 --- a/01OS/01OS/server/stt/local_service/whisper-rust/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb \ No newline at end of file diff --git a/01OS/01OS/server/stt/local_service/whisper-rust/Cargo.lock b/01OS/01OS/server/stt/local_service/whisper-rust/Cargo.lock deleted file mode 100644 index 27da1ff..0000000 --- a/01OS/01OS/server/stt/local_service/whisper-rust/Cargo.lock +++ /dev/null @@ -1,1228 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "alsa" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2562ad8dcf0f789f65c6fdaad8a8a9708ed6b488e649da28c01656ad66b8b47" -dependencies = [ - "alsa-sys", - "bitflags 1.3.2", - "libc", - "nix", -] - -[[package]] -name = "alsa-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "anstream" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bindgen" -version = "0.69.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c69fae65a523209d34240b60abe0c42d33d1045d445c0839d8a4894a736e2d" -dependencies = [ - "bitflags 2.4.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.48", - "which", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "jobserver", - "libc", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "coreaudio-rs" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" -dependencies = [ - "bitflags 1.3.2", - "core-foundation-sys", - "coreaudio-sys", -] - -[[package]] -name = "coreaudio-sys" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f01585027057ff5f0a5bf276174ae4c1594a2c5bde93d5f46a016d76270f5a9" -dependencies = [ - "bindgen", -] - -[[package]] -name = "cpal" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c" -dependencies = [ - "alsa", - "core-foundation-sys", - "coreaudio-rs", - "dasp_sample", - "jni 0.19.0", - "js-sys", - "libc", - "mach2", - "ndk", - "ndk-context", - "oboe", - "once_cell", - "parking_lot", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows", -] - -[[package]] -name = "dasp_sample" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "hound" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" - -[[package]] -name = "indexmap" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "mach2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" -dependencies = [ - "libc", -] - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "ndk" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" -dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys", - "num_enum", - "raw-window-handle", - "thiserror", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.4.1+23.1.7779620" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "nix" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "oboe" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0" -dependencies = [ - "jni 0.20.0", - "ndk", - "ndk-context", - "num-derive", - "num-traits", - "oboe-sys", -] - -[[package]] -name = "oboe-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2" -dependencies = [ - "cc", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "pkg-config" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" - -[[package]] -name = "prettyplease" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" -dependencies = [ - "proc-macro2", - "syn 2.0.48", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "walkdir" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" - -[[package]] -name = "web-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "whisper-rs" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e19ccc66e3746fc15cc9b8cbc67be61d7326f0dd313c3d5dce53e706365e23" -dependencies = [ - "whisper-rs-sys", -] - -[[package]] -name = "whisper-rs-sys" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91adc462e9bc7b3fce6116eeafe76f9bc46c20c2b4f5fe0da00fd1196fa92f1" -dependencies = [ - "bindgen", - "cfg-if", - "cmake", - "fs_extra", -] - -[[package]] -name = "whisper-rust" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "cpal", - "hound", - "whisper-rs", - "whisper-rs-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cad8365489051ae9f054164e459304af2e7e9bb407c958076c8bf4aef52da5" -dependencies = [ - "memchr", -] diff --git a/01OS/01OS/server/stt/local_service/whisper-rust/Cargo.toml b/01OS/01OS/server/stt/local_service/whisper-rust/Cargo.toml deleted file mode 100644 index f172692..0000000 --- a/01OS/01OS/server/stt/local_service/whisper-rust/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "whisper-rust" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = "1.0.79" -clap = { version = "4.4.18", features = ["derive"] } -cpal = "0.15.2" -hound = "3.5.1" -whisper-rs = "0.10.0" -whisper-rs-sys = "0.8.0" \ No newline at end of file diff --git a/01OS/01OS/server/stt/local_service/whisper-rust/README.md b/01OS/01OS/server/stt/local_service/whisper-rust/README.md deleted file mode 100644 index a4c8c02..0000000 --- a/01OS/01OS/server/stt/local_service/whisper-rust/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Setup - -To rebuild the `whisper-rust` executable, do the following: - -1. Install [Rust](https://www.rust-lang.org/tools/install), cmake, and Python dependencies `pip install -r requirements.txt`. -2. Go to **core/stt** and run `cargo build --release`. -3. Move the `whisper-rust` executable from target/release to this directory. diff --git a/01OS/01OS/server/stt/local_service/whisper-rust/src/main.rs b/01OS/01OS/server/stt/local_service/whisper-rust/src/main.rs deleted file mode 100644 index 0688c89..0000000 --- a/01OS/01OS/server/stt/local_service/whisper-rust/src/main.rs +++ /dev/null @@ -1,34 +0,0 @@ -mod transcribe; - -use clap::Parser; -use std::path::PathBuf; -use transcribe::transcribe; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - /// This is the model for Whisper STT - #[arg(short, long, value_parser, required = true)] - model_path: PathBuf, - - /// This is the wav audio file that will be converted from speech to text - #[arg(short, long, value_parser, required = true)] - file_path: Option, -} - -fn main() { - - let args = Args::parse(); - - let file_path = match args.file_path { - Some(fp) => fp, - None => panic!("No file path provided") - }; - - let result = transcribe(&args.model_path, &file_path); - - match result { - Ok(transcription) => print!("{}", transcription), - Err(e) => panic!("Error: {}", e), - } -} \ No newline at end of file diff --git a/01OS/01OS/server/stt/local_service/whisper-rust/src/transcribe.rs b/01OS/01OS/server/stt/local_service/whisper-rust/src/transcribe.rs deleted file mode 100644 index 35970cc..0000000 --- a/01OS/01OS/server/stt/local_service/whisper-rust/src/transcribe.rs +++ /dev/null @@ -1,64 +0,0 @@ -use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters}; -use std::path::PathBuf; - - -/// Transcribes the given audio file using the whisper-rs library. -/// -/// # Arguments -/// * `model_path` - Path to Whisper model file -/// * `file_path` - A string slice that holds the path to the audio file to be transcribed. -/// -/// # Returns -/// -/// A Result containing a String with the transcription if successful, or an error message if not. -pub fn transcribe(model_path: &PathBuf, file_path: &PathBuf) -> Result { - - let model_path_str = model_path.to_str().expect("Not valid model path"); - // Load a context and model - let ctx = WhisperContext::new_with_params( - model_path_str, // Replace with the actual path to the model - WhisperContextParameters::default(), - ) - .map_err(|_| "failed to load model")?; - - // Create a state - let mut state = ctx.create_state().map_err(|_| "failed to create state")?; - - // Create a params object - // Note that currently the only implemented strategy is Greedy, BeamSearch is a WIP - let mut params = FullParams::new(SamplingStrategy::Greedy { best_of: 1 }); - - // Edit parameters as needed - params.set_n_threads(1); // Set the number of threads to use - params.set_translate(true); // Enable translation - params.set_language(Some("en")); // Set the language to translate to English - // Disable printing to stdout - params.set_print_special(false); - params.set_print_progress(false); - params.set_print_realtime(false); - params.set_print_timestamps(false); - - // Load the audio file - let audio_data = std::fs::read(file_path) - .map_err(|e| format!("failed to read audio file: {}", e))? - .chunks_exact(2) - .map(|chunk| i16::from_ne_bytes([chunk[0], chunk[1]])) - .collect::>(); - - // Convert the audio data to the required format (16KHz mono i16 samples) - let audio_data = whisper_rs::convert_integer_to_float_audio(&audio_data); - - // Run the model - state.full(params, &audio_data[..]).map_err(|_| "failed to run model")?; - - // Fetch the results - let num_segments = state.full_n_segments().map_err(|_| "failed to get number of segments")?; - let mut transcription = String::new(); - for i in 0..num_segments { - let segment = state.full_get_segment_text(i).map_err(|_| "failed to get segment")?; - transcription.push_str(&segment); - transcription.push('\n'); - } - - Ok(transcription) -} \ No newline at end of file diff --git a/01OS/01OS/server/stt/local_service/whisper-rust/whisper-rust b/01OS/01OS/server/stt/local_service/whisper-rust/whisper-rust deleted file mode 100755 index 14a9042..0000000 Binary files a/01OS/01OS/server/stt/local_service/whisper-rust/whisper-rust and /dev/null differ diff --git a/01OS/01OS/server/tts/local_service/__init__.py b/01OS/01OS/server/tts/local_service/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/01OS/01OS/server/tts/tts.py b/01OS/01OS/server/tts/tts.py index 836a1dd..6106966 100644 --- a/01OS/01OS/server/tts/tts.py +++ b/01OS/01OS/server/tts/tts.py @@ -12,27 +12,28 @@ import os import subprocess import tempfile from pydub import AudioSegment -from pydub.playback import play -import simpleaudio as sa client = OpenAI() -def tts(text, play_audio): +chunk_size = 1024 + +def stream_tts(text): + """ + A generator that streams tts as LMC messages. + """ if os.getenv('ALL_LOCAL') == 'False': response = client.audio.speech.create( model="tts-1", voice="alloy", input=text, - response_format="mp3" + response_format="opus" ) - with tempfile.NamedTemporaryFile(suffix=".mp3") as temp_file: + with tempfile.NamedTemporaryFile(suffix=".opus") as temp_file: response.stream_to_file(temp_file.name) - - if play_audio: - audio = AudioSegment.from_mp3(temp_file.name) - play_audiosegment(audio) - return temp_file.read() + audio_bytes = temp_file.read() + file_type = "bytes.opus" + else: with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file: output_file = temp_file.name @@ -43,13 +44,19 @@ def tts(text, play_audio): '--output_file', output_file ], input=text, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - if play_audio: - audio = AudioSegment.from_wav(temp_file.name) - play_audiosegment(audio) - return temp_file.read() + audio_bytes = temp_file.read() + file_type = "bytes.wav" + + # Stream the audio + yield {"role": "assistant", "type": "audio", "format": file_type, "start": True} + for i in range(0, len(audio_bytes), chunk_size): + chunk = audio_bytes[i:i+chunk_size] + yield chunk + yield {"role": "assistant", "type": "audio", "format": file_type, "end": True} def play_audiosegment(audio): """ + UNUSED the default makes some pops. this fixes that """ @@ -73,3 +80,6 @@ def play_audiosegment(audio): # Wait for the playback to finish play_obj.wait_done() + # Delete the wav file + os.remove("output_audio.wav") + diff --git a/01OS/01OS/utils/accumulator.py b/01OS/01OS/utils/accumulator.py new file mode 100644 index 0000000..b6353cd --- /dev/null +++ b/01OS/01OS/utils/accumulator.py @@ -0,0 +1,44 @@ +class Accumulator: + def __init__(self): + self.template = {"role": None, "type": None, "format": None, "content": None} + self.message = self.template + + def accumulate(self, chunk): + #print(str(chunk)[:100]) + if type(chunk) == dict: + + if "format" in chunk and chunk["format"] == "active_line": + # We don't do anything with these + return None + + if "start" in chunk: + self.message = chunk + self.message.pop("start") + return None + + if "content" in chunk: + + # Display + print(chunk['content'], end="", flush=True) + + if any(self.message[key] != chunk[key] for key in self.message if key != "content"): + self.message = chunk + if "content" not in self.message: + self.message["content"] = chunk["content"] + else: + self.message["content"] += chunk["content"] + return None + + if "end" in chunk: + # We will proceed + message = self.message + self.message = self.template + return message + + if type(chunk) == bytes: + if "content" not in self.message or type(self.message["content"]) != bytes: + self.message["content"] = b"" + self.message["content"] += chunk + return None + + \ No newline at end of file diff --git a/01OS/_archive/device.py b/01OS/_archive/device.py index 3e71554..ee6eb55 100644 --- a/01OS/_archive/device.py +++ b/01OS/_archive/device.py @@ -122,7 +122,7 @@ def on_press(key): toggle_recording(True) def on_release(key): - """Detect spacebar release and ESC key press.""" + """Detect spacebar release and CTRL-C key press.""" if key == keyboard.Key.space: toggle_recording(False) elif key == keyboard.Key.esc: diff --git a/01OS/poetry.lock b/01OS/poetry.lock index 57c2429..66ee052 100644 --- a/01OS/poetry.lock +++ b/01OS/poetry.lock @@ -1890,6 +1890,31 @@ typing-extensions = ">=4.7,<5" [package.extras] datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] +[[package]] +name = "opencv-python" +version = "4.9.0.80" +description = "Wrapper package for OpenCV python bindings." +optional = false +python-versions = ">=3.6" +files = [ + {file = "opencv-python-4.9.0.80.tar.gz", hash = "sha256:1a9f0e6267de3a1a1db0c54213d022c7c8b5b9ca4b580e80bdc58516c922c9e1"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:7e5f7aa4486651a6ebfa8ed4b594b65bd2d2f41beeb4241a3e4b1b85acbbbadb"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:71dfb9555ccccdd77305fc3dcca5897fbf0cf28b297c51ee55e079c065d812a3"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b34a52e9da36dda8c151c6394aed602e4b17fa041df0b9f5b93ae10b0fcca2a"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4088cab82b66a3b37ffc452976b14a3c599269c247895ae9ceb4066d8188a57"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:dcf000c36dd1651118a2462257e3a9e76db789a78432e1f303c7bac54f63ef6c"}, + {file = "opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:3f16f08e02b2a2da44259c7cc712e779eff1dd8b55fdb0323e8cab09548086c0"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.21.0", markers = "python_version == \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, + {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, + {version = ">=1.19.3", markers = "platform_system == \"Linux\" and platform_machine == \"aarch64\" and python_version >= \"3.8\" and python_version < \"3.10\" or python_version > \"3.9\" and python_version < \"3.10\" or python_version >= \"3.9\" and platform_system != \"Darwin\" and python_version < \"3.10\" or python_version >= \"3.9\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, +] + [[package]] name = "packaging" version = "23.2" @@ -3514,4 +3539,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "12ccff8a2521e7eb88eee82cfd3de409fea8e1658406d6148a42f9347ca7b2a7" +content-hash = "5c8d587b405e97c0dca454078950157106f9aea687cbecce5b7ae7effd2aeece" diff --git a/01OS/pyproject.toml b/01OS/pyproject.toml index c36dcc3..5f4d26c 100644 --- a/01OS/pyproject.toml +++ b/01OS/pyproject.toml @@ -4,7 +4,7 @@ packages = [ {include = "01OS"}, ] include = [".env.example", "start.py", "start.sh"] -version = "0.0.2" +version = "0.0.3" description = "The open-source language model computer" authors = ["Killian "] license = "AGPL" @@ -25,6 +25,7 @@ pydub = "^0.25.1" ngrok = "^1.0.0" open-interpreter = "^0.2.0" simpleaudio = "^1.0.4" +opencv-python = "^4.9.0.80" [build-system] requires = ["poetry-core"] diff --git a/01OS/start.py b/01OS/start.py index ea734fa..886d332 100644 --- a/01OS/start.py +++ b/01OS/start.py @@ -19,5 +19,8 @@ def main(): command = [os.path.join(dir_path, 'start.sh')] + args # Start start.sh with the command line arguments - subprocess.run(command, check=True) + try: + subprocess.run(command, check=True) + except KeyboardInterrupt: + print("Exiting...") \ No newline at end of file diff --git a/01OS/start.sh b/01OS/start.sh index 36b7ec6..c78b99f 100755 --- a/01OS/start.sh +++ b/01OS/start.sh @@ -54,6 +54,16 @@ if [[ "$@" == *"--expose"* ]]; then export SERVER_EXPOSE_PUBLICALLY="True" fi +# Check if "--clear-local" is passed as an argument +if [[ "$@" == *"--clear-local"* ]]; then + # If "--clear-local" is passed, clear the contents of the folders in script_dir/01OS/server/{tts and stt}/local_service + echo "Clearing local services..." + rm -rf "$SCRIPT_DIR/01OS/server/tts/local_service"/* + rm -rf "$SCRIPT_DIR/01OS/server/stt/local_service"/* + echo "Exiting after clearing local services..." + exit 0 +fi + ### SETUP if [[ "$ALL_LOCAL" == "True" ]]; then @@ -124,7 +134,7 @@ fi start_client() { echo "Starting client..." - bash 01OS/clients/start.sh & + bash $SCRIPT_DIR/01OS/clients/start.sh & CLIENT_PID=$! echo "client started as process $CLIENT_PID" }