From 6120e7ba5765798905dbeb50990204356f047804 Mon Sep 17 00:00:00 2001 From: ZZY <2450266535@qq.com> Date: Sat, 31 Aug 2024 14:36:44 +0800 Subject: [PATCH] =?UTF-8?q?refactor(main):=20=E4=BD=BF=E7=94=A8=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E6=B5=81=E5=A4=84=E7=90=86=E6=9B=BF=E6=8D=A2=E5=8E=9F?= =?UTF-8?q?=E6=9C=89=E7=9A=84=E9=A1=BA=E5=BA=8F=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构`main`函数,将原先的顺序执行模型改为基于异步流的处理方式,利用`aiostream`库实现更高效的并发数据处理。 --- main.py | 64 +-- plugins/example.py | 10 +- requirements.txt | 8 + src/__init__.py | 20 - src/core/core.py | 483 --------------------- src/core/interface.py | 0 src/core/tools.py | 15 - src/{offical => dashscope}/__init__.py | 0 src/{offical => }/dashscope/paraformer.py | 5 +- src/{offical => }/dashscope/sambert.py | 64 ++- src/dashscope/tongyiqianwen.py | 78 ++++ src/engine/asr_engine.py | 5 - src/engine/chat_ai_engine.py | 10 - src/engine/nlu_engine.py | 5 - src/engine/stream_engine.py | 56 --- src/engine/tts_engine.py | 5 - src/offical/dashscope/__init__.py | 7 - src/offical/requests/__init__.py | 5 - src/offical/requests/remote_engine.py | 25 -- src/offical/requests/tongyiqianwen.py | 74 ---- src/offical/sounds/__init__.py | 4 - src/offical/sounds/sounds_play_engine.py | 35 -- src/offical/sounds/sounds_record_engine.py | 2 - src/offical/sounds/sounds_wrapper.py | 9 - src/plugins/__init__.py | 0 src/plugins/dynamic_package_import.py | 61 --- src/plugins/plugins.py | 38 -- src/plugins/plugins_conf.py | 54 --- src/plugins/plugins_import.py | 48 -- src/pyaudio/sounds_play_engine.py | 23 + src/utils/logger.py | 0 tests/core/__init__.py | 0 tests/core/test_core.py | 54 --- tests/core/test_echo.py | 13 - tests/offical/sounds/asr_example.wav | Bin 128480 -> 0 bytes tests/offical/sounds/test_sounds_wapper.py | 72 --- tests/plugins/__init__.py | 0 37 files changed, 168 insertions(+), 1184 deletions(-) delete mode 100644 src/core/core.py delete mode 100644 src/core/interface.py delete mode 100644 src/core/tools.py rename src/{offical => dashscope}/__init__.py (100%) rename src/{offical => }/dashscope/paraformer.py (91%) rename src/{offical => }/dashscope/sambert.py (54%) create mode 100644 src/dashscope/tongyiqianwen.py delete mode 100644 src/engine/asr_engine.py delete mode 100644 src/engine/chat_ai_engine.py delete mode 100644 src/engine/nlu_engine.py delete mode 100644 src/engine/stream_engine.py delete mode 100644 src/engine/tts_engine.py delete mode 100644 src/offical/dashscope/__init__.py delete mode 100644 src/offical/requests/__init__.py delete mode 100644 src/offical/requests/remote_engine.py delete mode 100644 src/offical/requests/tongyiqianwen.py delete mode 100644 src/offical/sounds/__init__.py delete mode 100644 src/offical/sounds/sounds_play_engine.py delete mode 100644 src/offical/sounds/sounds_record_engine.py delete mode 100644 src/offical/sounds/sounds_wrapper.py delete mode 100644 src/plugins/__init__.py delete mode 100644 src/plugins/dynamic_package_import.py delete mode 100644 src/plugins/plugins.py delete mode 100644 src/plugins/plugins_conf.py delete mode 100644 src/plugins/plugins_import.py create mode 100644 src/pyaudio/sounds_play_engine.py delete mode 100644 src/utils/logger.py delete mode 100644 tests/core/__init__.py delete mode 100644 tests/core/test_core.py delete mode 100644 tests/core/test_echo.py delete mode 100644 tests/offical/sounds/asr_example.wav delete mode 100644 tests/offical/sounds/test_sounds_wapper.py delete mode 100644 tests/plugins/__init__.py diff --git a/main.py b/main.py index ae0cbbb..d6a2706 100644 --- a/main.py +++ b/main.py @@ -1,50 +1,34 @@ # from src import Plugins -from src import ExecutePipeline -from src import EchoProcessor +# from src import ExecutePipeline +# from src import EchoProcessor +import os from viztracer import VizTracer -async def main(): - from pathlib import Path +from dotenv import load_dotenv +load_dotenv() - # plug_conf = Plugins(Path(__file__).resolve().parent) - from src.offical.requests.tongyiqianwen import ChatAiTongYiQianWen - pipe = ExecutePipeline([ - ChatAiTongYiQianWen(api_key='sk-ab4a3e0e29d54ebaad560c1472933d41', use_stream_api=True), - EchoProcessor() - ]).start() - # # plug_conf.load_engine("asr_engine"), - # # MyEngine(), - # plug_conf.load_engine("chat_ai_engine"), - # TeeProcessor(), - # plug_conf.load_engine("tts_engine"), - # plug_conf.load_engine("sounds_play_engine"), - # EchoEngine() - # exe_input = './tests/offical/sounds/asr_example.wav' - # exe_input = input('input: ') +from pathlib import Path +from src.dashscope.tongyiqianwen import CAITongYiQianWen as CAI +from src.dashscope.sambert import TTSSambert as TTS +from src.pyaudio.sounds_play_engine import SoundsPlayEngine as sounds +from aiostream import stream, pipe + +async def main(): + + cai = CAI(api_key=os.environ.get("DASH_SCOPE_API_KEY", ""), use_stream_api=True) + tts = TTS(api_key=os.environ.get("DASH_SCOPE_API_KEY", "")) exe_input = '给我一个100字的文章' - await pipe.write(exe_input) - await asyncio.sleep(0) - # loop.run_in_executor(None, inputdata) - loop = asyncio.get_running_loop() - def inputdata(pipe, loop): - while True: - try: - data = input('input :') - asyncio.run_coroutine_threadsafe(pipe.write(data), loop) - except KeyboardInterrupt: - pipe.cancel() - break + with VizTracer(log_async=True): - thread = threading.Thread(target=inputdata, args=(pipe,loop,)) - thread.start() - await pipe.process() - thread.join() - # asyncio.gather([i for i in pipe._tasks]) - # await asyncio.to_thread(inputdata, pipe) + s = ( + stream.iterate(await cai.execute_stream(cai.prepare_input(exe_input))) + | pipe.map(cai.transform_chunks) + | pipe.print() + | pipe.flatmap(tts.execute_stream) + | pipe.map(sounds().execute) + ) + await s if __name__ == '__main__': - from dotenv import load_dotenv - load_dotenv() import asyncio - import threading asyncio.run(main()) diff --git a/plugins/example.py b/plugins/example.py index 9dd2cd7..bc3fef5 100644 --- a/plugins/example.py +++ b/plugins/example.py @@ -1,8 +1,8 @@ -from src import Engine +from aiostream import stream, pipe, Stream -class MyEngine(Engine): +class MyExecute(): def __init__(self): - super().__init__() - + pass + def execute(self, data): - print(data) \ No newline at end of file + pass \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8a47f2e..c1491e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,13 @@ python-dotenv # server optional # tornado +# async part +aiohttp +aiostream + +# debug part +viztracer + +# optional tqdm rich # optional \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py index be81001..5331c2e 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,23 +1,3 @@ -# from .core.interface import MiddlewareInterface as MiddlewareInterface -# from .core.interface import EngineInterface as EngineInterface - -from .core.core import ExecuteDataStream as ExecuteDataStream -from .core.core import ExecuteProcessor as ExecuteProcessor -from .core.core import ExecutePipeline as ExecutePipeline -from .core.tools import EchoProcessor as EchoProcessor -from .core.tools import TeeProcessor as TeeProcessor - -# from .engine.stream_engine import StreamEngine as StreamEngine -# from .engine.asr_engine import ASREngine as ASREngine -# from .engine.tts_engine import TTSEngine as TTSEngine -# from .engine.nlu_engine import NLUEngine as NLUEngine -# from .engine.chat_ai_engine import ChatAIEngine as ChatAIEngine - -# from .plugins.dynamic_package_import import dynamic_package_import as dynamic_package_import -# from .plugins.plugins_conf import PluginsConfig as PluginsConfig -# from .plugins.plugins import Plugins as Plugins - -# from .utils.logger import setup_logger as setup_logger import logging from sys import stdout logger = logging.getLogger(__name__) diff --git a/src/core/core.py b/src/core/core.py deleted file mode 100644 index 67aaf50..0000000 --- a/src/core/core.py +++ /dev/null @@ -1,483 +0,0 @@ -from abc import ABC, abstractmethod -import asyncio -from typing import Any, AsyncGenerator, Coroutine -from logging import getLogger -logger = getLogger(__name__) - -class ExecuteDataStream: - """ - Represents a stream of data with associated metadata. - - This class provides methods to manage a stream of data, including reading and writing data - asynchronously. It uses an asyncio Queue to store data items and manages metadata such as - the name of the stream and its operational status. - - Attributes: - - __metadata: A dictionary containing metadata about the data stream. - - __data_queue: An asyncio Queue for storing data items. - - 表示了含有元数据的数据流。 - - 该类提供了用于管理数据流的方法,包括异步读写数据。它使用 asyncio 队列来存储数据项, - 并管理诸如数据流名称和操作状态等元数据。 - - 属性: - - __metadata: 包含关于数据流元数据的字典。 - - __data_queue: 用于存储数据项的 asyncio 队列。 - """ - def __init__(self, - name: str = "ExecuteDataStream", - maxsize: int = 8): - """ - Initialize the ExecuteDataStream with an empty data buffer and metadata dictionary. - - Parameters: - - name: str, the name of the ExecuteDataStream, defaults to "ExecuteDataStream". - - maxsize: int, the maximum size of the data queue, defaults to 8. - - 初始化 ExecuteDataStream 类的一个实例,创建一个空的数据缓冲区和元数据字典。 - - 参数: - - name: str, 数据流的名字,默认为 "ExecuteDataStream"。 - - maxsize: int, 数据队列的最大容量,默认为 8。 - """ - self.__metadata = { - "__name__": name, - "__running__": True, - "__open_life__": True, - } - self.__data_queue = asyncio.Queue(maxsize) - - async def iter_read(self, timeout: float | None = None) -> AsyncGenerator: - """ - Asynchronously iterate over data in the stream, yielding each item as it becomes available. - - Parameters: - - timeout: float | None, the time to wait for data before timing out. - - Returns: - - AsyncGenerator: An asynchronous generator that yields data items as they become available. - - 异步迭代数据流中的数据,当数据可用时生成每个数据项(阻塞等待数据)。 - - 参数: - - timeout: float | None, 等待数据的时间,超时则停止等待。 - - 返回: - - AsyncGenerator: 当数据可用时生成数据项的异步生成器。 - """ - while True: - res = await self.read(timeout) - if res is None: - break - yield res - - async def read(self, timeout: float | None = None) -> Any | None: - """ - Asynchronously read data from the data stream. - - Parameters: - - timeout: float | None, the time to wait for data before timing out. - - Returns: - - Any | None: The data item or None if no data is available within the timeout period. - - 异步从数据流中读取数据。 - - 参数: - - timeout: float | None, 等待数据的时间,超时则停止等待。 - - 返回: - - Any | None: 数据项或 None ,如果在超时期间内没有数据可用。 - """ - if not self.__metadata.get('__running__', False): - return None - - try: - data = await asyncio.wait_for(self.__data_queue.get(), timeout) - return data.get("data", None) - except asyncio.TimeoutError: - return None - - async def write(self, - data: Any, - timeout: float | None = None, - life_time: int = -1) -> bool: - """ - Asynchronously write data to the data stream. - - #### Note: Please do not write None as it will be considered an error and thus discarded. - - Parameters: - - data: Any, the data to be written. - - timeout: float | None, the time to wait for writing before timing out. - - life_time: int, the number of iterations the data should remain in the stream. - - Returns: - - bool: True if the data was successfully written, False otherwise. - - 异步向数据流中写入数据。 - - #### 注意请不要写入 None 因为 None 会被认为是 Error ,所以会被抛弃 。 - - 参数: - - data: Any, 要写入的数据。 - - timeout: float | None, 写入等待时间,超时则停止等待。 - - life_time: int, 数据在数据流中的存活周期数。 - - 返回: - - bool: 如果数据成功写入则返回 True ,否则返回 False。 - """ - if not self.__metadata.get('__running__', False): - return False - try: - if life_time == 0 or data is None: - return False - if self.__metadata.get('__open_life__', False): - life_time -= 1 - await asyncio.wait_for(self.__data_queue.put({ - 'data': data, - 'life': life_time, - }), timeout) - return True - except asyncio.TimeoutError: - return False - - -class ExecuteProcessor(ABC): - """ - An abstract base class for processing data streams. - - This class represents a processor that can handle incoming data from one stream and send processed data to another stream. - - Usage: - - Inherit from this class and implement the `execute` method. - - Call the `set_stream` method to set `read_stream` and `write_stream`. - - Call the `process` method to start the processor (if there are custom requirements, you can refactor this function, but the refactoring must comply with the interface standard). - - Attributes: - - _read_stream: (Should not be used directly) An instance of `ExecuteDataStream` for reading data. - - _write_stream: (Should not be used directly) An instance of `ExecuteDataStream` for writing data. - - 一个抽象基类,用于处理数据流。 - - 该类表示一个处理器,可以从一个数据流读取数据,并将处理后的数据发送到另一个数据流。 - - 使用方法: - - 继承该类并实现 `execute` 方法。 - - 调用 `set_stream` 方法设置 `read_stream` 和 `write_stream`。 - - 调用 `process` 方法启动处理器(如果有定制化要求可重构该函数,但重构必须符合接口标准)。 - - 属性: - - _read_stream: (不应当直接使用)用于读取数据的 `ExecuteDataStream` 实例。 - - _write_stream: (不应当直接使用)用于写入数据的 `ExecuteDataStream` 实例。 - """ - def __init__(self): - """ - Initialize the `ExecuteProcessor` with default read and write streams set to `None`. - - 初始化 `ExecuteProcessor` 类的一个实例,将默认的读取和写入数据流设置为 `None`。 - """ - self._read_stream: ExecuteDataStream | None = None - self._write_stream: ExecuteDataStream | None = None - - def set_stream(self, - read_stream: ExecuteDataStream | None = None, - write_stream: ExecuteDataStream | None = None): - """ - Set the read and write streams for this processor. - - #### Note: Once `read_stream` and `write_stream` are set, this instance should not accept new settings. - - Parameters: - - read_stream: An instance of `ExecuteDataStream` for reading data. - - write_stream: An instance of `ExecuteDataStream` for writing data. - - 设置此处理器的读取和写入数据流。 - - #### 注意一旦设置了 `read_stream` 和 `write_stream` ,则该实例将不应该接受新的设置。 - - 参数: - - read_stream: 用于读取数据的 `ExecuteDataStream` 实例。 - - write_stream: 用于写入数据的 `ExecuteDataStream` 实例。 - """ - self._read_stream = read_stream or self._read_stream - self._write_stream = write_stream or self._write_stream - - async def _iter_process(self): - """ - Iterate over the data in the read stream and process it, then write the results to the write stream. - - #### Note: If the `process` method is refactored in the future, this function may serve as a scaffold. - - 迭代读取数据流中的数据并对其进行处理,然后将结果写入写入数据流。 - - #### 注意如果未来重构 `process` 方法,可能需要该函数作为脚手架。 - """ - if self._read_stream is None or self._write_stream is None: - raise ValueError("read_stream or write_stream is None") - try: - async for data in self._read_stream.iter_read(): - result = await self.execute(data) - if isinstance(result, AsyncGenerator): - async for res in result: - await self._write_stream.write(res) - await asyncio.sleep(0) - else: - await self._write_stream.write(result) - await asyncio.sleep(0) - except Exception as e: - logger.exception(f"An error occurred during processing: {e}") - # await self._write_stream.write(e) - - @abstractmethod - async def execute(self, data) -> AsyncGenerator[Any, Any] | Coroutine[Any, Any, Any]: - """ - Process the given data. - - Parameters: - - data: The data to be processed. - - Returns: - - AsyncGenerator | Any: The processed data or an asynchronous generator of processed data. - - 处理给定的数据。 - - 参数: - - data: 要处理的数据。 - - 返回: - - AsyncGenerator | Any: 处理后的数据或处理后数据的异步生成器。 - """ - pass - - async def process(self): - """ - Future entry point for starting the processor. - - 未来启动处理器的调用入口。 - """ - await self._iter_process() - - -class ExecutePipeline(ExecuteProcessor): - """ - A class representing a pipeline of processors. - - This class manages a sequence of `ExecuteProcessor` instances and coordinates their execution. - - Attributes: - - _processors: A list of `ExecuteProcessor` instances. - - _streams: A list of `ExecuteDataStream` instances, including the first and last streams which can be set externally. - - _tasks: A list of asyncio Tasks representing the execution of each processor. - - 一个表示处理器管道的类。 - - 该类管理一系列 `ExecuteProcessor` 实例,并协调它们的执行。 - - 属性: - - _processors: `ExecuteProcessor` 实例列表。 - - _streams: `ExecuteDataStream` 实例列表,包括可以外部设置的第一个和最后一个数据流。 - - _tasks: 表示每个处理器执行的 asyncio Task 列表。 - """ - - def __init__(self, processors: list[ExecuteProcessor]): - """ - Initialize the `ExecutePipeline` with a list of processors. - - Parameters: - - processors: A list of `ExecuteProcessor` instances. - - 使用处理器列表初始化 `ExecutePipeline`。 - - 参数: - - processors: `ExecuteProcessor` 实例列表。 - """ - self._processors = processors - self._streams = [None] + [ExecuteDataStream() for _ in range(len(self._processors) - 1)] + [None] - self._tasks:list[asyncio.Task] = [] - self.__is_executed = False - - def set_stream(self, - read_stream: ExecuteDataStream | None = None, - write_stream: ExecuteDataStream | None = None): - """ - Set the input and output streams for the pipeline. - - Parameters: - - read_stream: The input stream for the pipeline. - - write_stream: The output stream for the pipeline. - - 设置管道的输入和输出数据流。 - - 参数: - - read_stream: 管道的输入数据流。 - - write_stream: 管道的输出数据流。 - """ - self._streams[0] = write_stream or self._streams[0] - self._streams[-1] = read_stream or self._streams[-1] - - def _get_stream(self, index: int) -> ExecuteDataStream: - """ - Get the stream at the specified index. - - Parameters: - - index: The index of the stream to retrieve. - - Returns: - - ExecuteDataStream: The stream at the specified index. - - 获取指定索引处的数据流。 - - 参数: - - index: 要获取的数据流的索引。 - - 返回: - - ExecuteDataStream: 指定索引处的数据流。 - """ - stream = self._streams[index] - if stream is None: - raise ValueError("Stream not found") - return stream - - async def write(self, - data, - index = 0, - timeout = None, - life_time = -1): - """ - Write data to the pipeline's input data stream. - - Parameters: - - data: The data to write. - - index: The index of the stream to write to. Default is 0 (the first stream). - - timeout: The timeout for writing the data. - - life_time: The life time of the data. - - 将数据写入管道的输入数据流。 - - 参数: - - data: 要写入的数据。 - - index: 写入数据的数据流索引,默认为 0 (第一个数据流)。 - - timeout: 写入数据的超时时间。 - - life_time: 数据的生命周期。 - """ - await self._get_stream(index).write(data, timeout, life_time) - - async def read(self, index: int = -1, timeout: float | None = None): - """ - Read data from the last processor's data stream. - - Parameters: - - index: The index of the stream to read from. Default is -1 (the last stream). - - timeout: The timeout for reading the data. - - Returns: - - Any: The data read from the stream. - - 从最后一个处理器的数据流中读取数据。 - - 参数: - - index: 读取数据的数据流索引,默认为 -1 (最后一个数据流)。 - - timeout: 读取数据的超时时间。 - - 返回: - - Any: 从数据流中读取的数据。 - """ - return await self._get_stream(index).read(timeout) - - def iter_read(self, index: int = -1, timeout: float | None = None): - """ - Iterate over the data in the specified stream. - - Parameters: - - index: The index of the stream to iterate over. Default is -1 (the last stream). - - timeout: The timeout for reading the data. - - Returns: - - AsyncIterator: An asynchronous iterator over the data in the stream. - - 迭代指定数据流中的数据。 - - 参数: - - index: 迭代数据的数据流索引,默认为 -1 (最后一个数据流)。 - - timeout: 读取数据的超时时间。 - - 返回: - - AsyncIterator: 对数据流中的数据进行迭代的异步迭代器。 - """ - return self._get_stream(index).iter_read(timeout) - - def cancel(self): - """ - Cancel all running tasks in the pipeline. - - 取消管道中所有正在运行的任务。 - """ - if self._tasks is None: - return - for task in self._tasks: - task.cancel() - - def start(self): - """ - Start the pipeline by executing the `execute` method. - - 通过执行 `execute` 方法来启动管道。 - """ - self.set_stream(ExecuteDataStream(), ExecuteDataStream()) - self.execute() - return self - - def execute(self): - """ - Execute the pipeline by setting up the streams for each processor and creating tasks for their execution. - - 通过为每个处理器设置数据流并为其执行创建任务来执行管道。 - """ - if self.__is_executed: - return - self.__is_executed = True - for i, processor in enumerate(self._processors): - processor.set_stream(self._get_stream(i), self._get_stream(i + 1)) - self._tasks.append( - asyncio.create_task(processor.process()) - ) - - async def process(self): - """ - Execute the pipeline and wait for all tasks to complete. - - 执行管道并等待所有任务完成。 - """ - self.execute() - await asyncio.gather(*self._tasks) - -# 示例处理器 -class ExampleProcessor(ExecuteProcessor): - - async def execute(self, data): - return data + " processed" - -async def main(): - processors:list[ExecuteProcessor] = [ExampleProcessor()] - pipeline = ExecutePipeline(processors) - pipeline.start() - - input_data = "Hello, world!" - await pipeline.write(input_data) - print("Pipeline started.") - async def fun(): - async for data in pipeline.iter_read(): - print(data) - task = asyncio.create_task(fun()) - - while True: - data = input("input data: ") - await pipeline.write(data) - await asyncio.sleep(0) - # print(await pipeline.read()) - -# 使用示例 -if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file diff --git a/src/core/interface.py b/src/core/interface.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/tools.py b/src/core/tools.py deleted file mode 100644 index 50c11aa..0000000 --- a/src/core/tools.py +++ /dev/null @@ -1,15 +0,0 @@ -from sys import stdout -from typing import Any, AsyncGenerator -from .core import ExecuteProcessor - -class EchoProcessor(ExecuteProcessor): - async def execute(self, data): - stdout.write(data) - stdout.flush() - return None - -class TeeProcessor(ExecuteProcessor): - async def execute(self, data): - stdout.write(data) - stdout.flush() - return data \ No newline at end of file diff --git a/src/offical/__init__.py b/src/dashscope/__init__.py similarity index 100% rename from src/offical/__init__.py rename to src/dashscope/__init__.py diff --git a/src/offical/dashscope/paraformer.py b/src/dashscope/paraformer.py similarity index 91% rename from src/offical/dashscope/paraformer.py rename to src/dashscope/paraformer.py index 976fb28..6a0523b 100644 --- a/src/offical/dashscope/paraformer.py +++ b/src/dashscope/paraformer.py @@ -2,7 +2,6 @@ import json from typing import Any -from src import ASREngine as ASREngine from http import HTTPStatus import dashscope @@ -19,12 +18,11 @@ logger = getLogger(__name__) # with open('asr_example.wav', 'wb') as f: # f.write(r.content) -class ASRParaformer(ASREngine): +class ASRParaformer(): def __init__(self, api_key : str, _model : str = "paraformer-realtime-v1", _is_stream : bool = False, *args, **kwargs) -> None: - super().__init__() dashscope.api_key = api_key self.recognition = Recognition(kwargs.get("model", _model), format='wav', @@ -34,7 +32,6 @@ class ASRParaformer(ASREngine): def process_output(self, data): corrected_data = data.replace("'", '"') res = json.loads(corrected_data)["text"] - return super().process_output(res) def execute(self, data: Any) -> Any: result = self.recognition.call(data) diff --git a/src/offical/dashscope/sambert.py b/src/dashscope/sambert.py similarity index 54% rename from src/offical/dashscope/sambert.py rename to src/dashscope/sambert.py index 203f5c2..53e4df2 100644 --- a/src/offical/dashscope/sambert.py +++ b/src/dashscope/sambert.py @@ -1,16 +1,16 @@ # https://help.aliyun.com/zh/dashscope/developer-reference/quick-start-13?spm=a2c4g.11186623.0.0.26772e5cs8Vl59 +import asyncio import sys from typing import Any, Generator, Iterable, Iterator -from src import TTSEngine as TTSEngine import dashscope from dashscope.api_entities.dashscope_response import SpeechSynthesisResponse from dashscope.audio.tts import ResultCallback, SpeechSynthesizer, SpeechSynthesisResult +from aiostream import Stream, stream from logging import getLogger -from src import StreamEngine as StreamEngine logger = getLogger(__name__) # import requests @@ -20,23 +20,20 @@ logger = getLogger(__name__) # with open('asr_example.wav', 'wb') as f: # f.write(r.content) -class TTSSambert(TTSEngine, StreamEngine): +class TTSSambert(): def __init__(self, api_key : str, _model : str = "sambert-zhichu-v1", _is_stream : bool = False, *args, **kwargs) -> None: - TTSEngine.__init__(self) - StreamEngine.__init__(self, - use_stream_api=kwargs.get('use_stream_api', False), - return_as_stream=kwargs.get('return_as_stream', False)) dashscope.api_key = api_key self.model = kwargs.get("model", _model) class Callback(ResultCallback): - def __init__(self, generator) -> None: + def __init__(self)-> None: + self.res = [] super().__init__() - self.generator = generator + def on_open(self): logger.debug('Speech synthesizer is opened.') @@ -46,38 +43,35 @@ class TTSSambert(TTSEngine, StreamEngine): def on_error(self, response: SpeechSynthesisResponse): logger.error('Speech synthesizer failed, response is %s' % (str(response))) def on_close(self): - self.generator.send(None) logger.debug('Speech synthesizer is closed.') def on_event(self, result: SpeechSynthesisResult): if result.get_audio_frame() is not None: logger.debug('audio result length:', sys.getsizeof(result.get_audio_frame())) - res = result.get_audio_frame() - self.generator.send(res) - + self.res.append(result.get_audio_frame()) + if result.get_timestamp() is not None: logger.debug('timestamp result:', str(result.get_timestamp())) + async def generate_events(self, callback: Callback): + for event in callback.res: + yield event - def execute_nonstream(self, data) -> bytes: - result = SpeechSynthesizer.call(model=self.model, - text=data, - sample_rate=48000) - return result.get_audio_data() - - # def execute_stream(self, data) -> Generator[Any, None, None] | Iterator: - # pass - # if self._is_stream: - # def audio_generator(): - # while True: - # data = yield - # if data is None: - # break - # gen = audio_generator() - # next(gen) - # callback = self.Callback(gen) - # SpeechSynthesizer.call(model=self.model, + async def process_events(self, callback: Callback) -> Stream[bytes]: + source = self.generate_events(callback) + return stream.iterate(source) + + # def execute_nonstream(self, data) -> bytes: + # result = SpeechSynthesizer.call(model=self.model, # text=data, - # sample_rate=48000, - # callback=callback, - # word_timestamp_enabled=True, - # phoneme_timestamp_enabled=True) \ No newline at end of file + # sample_rate=48000) + # return result.get_audio_data() + + def execute_stream(self, data, *args): + callback = self.Callback() + SpeechSynthesizer.call(model=self.model, + text=data, + sample_rate=48000, + callback=callback, + word_timestamp_enabled=True, + phoneme_timestamp_enabled=True) + return self.generate_events(callback) \ No newline at end of file diff --git a/src/dashscope/tongyiqianwen.py b/src/dashscope/tongyiqianwen.py new file mode 100644 index 0000000..b2af83f --- /dev/null +++ b/src/dashscope/tongyiqianwen.py @@ -0,0 +1,78 @@ +# https://dashscope.console.aliyun.com/model +import json +import aiohttp + +from logging import getLogger +logger = getLogger(__name__) + +class CAITongYiQianWen(): + API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation" + def __init__(self, api_key : str, + _model : str = "qwen-1.8b-chat", + *args, **kwargs) -> None: + self.api_key = api_key + self._modual_name = kwargs.get("model", _model) + self.use_stream_api=kwargs.get("use_stream_api", False) + + def _transform_raw(self, response) -> str: + return response["output"]["choices"][0]["message"]["content"] + + def transform_chunks(self, response: str, *args): + current_msg = '' + for line in response.splitlines(): + if line.startswith("data:"): + current_msg += line[5:].strip() + elif len(line) == 0: + if current_msg: + return self._transform_raw(json.loads(current_msg)) + + async def post_prompt(self, messages: dict = {}, is_stream: bool = False, header: dict[str, str] = {}): + try: + async with aiohttp.ClientSession() as client: + async with client.post(self.API_URL, + headers={ + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + self.api_key, + **header, + None if not is_stream else 'X-DashScope-SSE': 'enable' + }, + json=messages) as response: + if is_stream: + async for chunk in response.content.iter_any(): + yield chunk.decode('utf-8') + else: + data = await response.read() + yield data.decode('utf-8') + except Exception as e: + logger.exception("post_prompt") + raise e + + async def execute_stream(self, data): + response = self.post_prompt({ + 'model': self._modual_name, + "input": { + "messages": data + }, + "parameters": { + "result_format": "message", + "incremental_output": True + } + }, is_stream = True) + return response + + async def execute_nonstream(self, data): + response = self.post_prompt({ + 'model': self._modual_name, + "input": { + "messages": data + }, + "parameters": { + "result_format": "message", + "incremental_output": False + } + }) + # ret = response.json() + # return self._transform_raw(ret) + + def prepare_input(self, data): + return [{'role': 'user', 'content': f'{data}'}] \ No newline at end of file diff --git a/src/engine/asr_engine.py b/src/engine/asr_engine.py deleted file mode 100644 index db1830e..0000000 --- a/src/engine/asr_engine.py +++ /dev/null @@ -1,5 +0,0 @@ -from .. import Engine - -class ASREngine(Engine): - def __init__(self) -> None: - super().__init__() diff --git a/src/engine/chat_ai_engine.py b/src/engine/chat_ai_engine.py deleted file mode 100644 index efa7935..0000000 --- a/src/engine/chat_ai_engine.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Dict, Optional -from logging import getLogger -logger = getLogger(__name__) -from .. import Engine - -class ChatAIEngine(Engine): - """基础AI引擎类, 提供历史记录管理的基础框架。""" - def __init__(self, history: Optional[Dict] = None) -> None: - self._history = history - Engine.__init__(self) \ No newline at end of file diff --git a/src/engine/nlu_engine.py b/src/engine/nlu_engine.py deleted file mode 100644 index 6ccc317..0000000 --- a/src/engine/nlu_engine.py +++ /dev/null @@ -1,5 +0,0 @@ -from .. import Engine - -class NLUEngine(Engine): - def __init__(self, is_stream: bool = False) -> None: - super().__init__(is_stream) \ No newline at end of file diff --git a/src/engine/stream_engine.py b/src/engine/stream_engine.py deleted file mode 100644 index 8473ea3..0000000 --- a/src/engine/stream_engine.py +++ /dev/null @@ -1,56 +0,0 @@ -from typing import Any, Generator, Iterable, Iterator -from .. import Engine - -class StreamEngine(Engine): - def __init__(self, use_stream_api: bool = False, return_as_stream: bool = False): - self._use_stream_api = use_stream_api - self._return_as_stream = return_as_stream - - def execute_stream(self, data) -> Generator | Iterator: - raise NotImplementedError - - def execute_nonstream(self, data) -> Any: - raise NotImplementedError - - def _execute_stream(self, data: Any, return_as_stream: bool) -> Any: - results = self.execute_stream(data) - return results if return_as_stream else list(results) - - def _execute_nonstream(self, data: Any, return_as_stream: bool) -> Any: - result = self.execute_nonstream(data) - if return_as_stream: - def _(): - yield from result - return _() - else: - return result - - def execute(self, data: Any) -> Any: - if not isinstance(data, Generator) or isinstance(data, bytes): - if self._use_stream_api: - return self._execute_stream([data], self._return_as_stream) - else: - return self._execute_nonstream(data, self._return_as_stream) - else: - if self._use_stream_api: - if self._return_as_stream: - def stream_results(): - for item in data: - yield from self._execute_stream([item], True) - return stream_results() - else: - return [self._execute_stream([item], False) for item in data] - else: - if self._return_as_stream: - def non_stream_results(): - for item in data: - yield self._execute_nonstream(item, False) - return non_stream_results() - else: - res = self._execute_nonstream(next(data), False) - for item in data: - _ = self._execute_nonstream(item, False) - if _ is None: - continue - res += _ - return res \ No newline at end of file diff --git a/src/engine/tts_engine.py b/src/engine/tts_engine.py deleted file mode 100644 index b02b427..0000000 --- a/src/engine/tts_engine.py +++ /dev/null @@ -1,5 +0,0 @@ -from .. import Engine - -class TTSEngine(Engine): - def __init__(self, is_stream: bool = False) -> None: - super().__init__(is_stream) \ No newline at end of file diff --git a/src/offical/dashscope/__init__.py b/src/offical/dashscope/__init__.py deleted file mode 100644 index fa572e0..0000000 --- a/src/offical/dashscope/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -import logging -logger = logging.getLogger(__name__) - -from src import dynamic_package_import -dynamic_package_import([ - ('dashscope', None), - ]) \ No newline at end of file diff --git a/src/offical/requests/__init__.py b/src/offical/requests/__init__.py deleted file mode 100644 index b732b29..0000000 --- a/src/offical/requests/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ - -# from src import dynamic_package_import -# dynamic_package_import([ -# ('requests', None), -# ]) \ No newline at end of file diff --git a/src/offical/requests/remote_engine.py b/src/offical/requests/remote_engine.py deleted file mode 100644 index 04b0785..0000000 --- a/src/offical/requests/remote_engine.py +++ /dev/null @@ -1,25 +0,0 @@ -from logging import getLogger -from typing import Any, Dict -logger = getLogger(__name__) -import requests -import httpx - -class RemoteEngine(): - """基础远程服务类, 提供远程调用的基础框架。""" - def __init__(self, api_key: str, base_url: str): - self._api_key = api_key - self._base_url = base_url - self.url = self._base_url - self.header = { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + self._api_key - } - - async def post_prompt(self, messages : Dict) -> httpx.Response: - try: - async with httpx.AsyncClient() as client: - response = await client.post(self.url, headers=self.header, json=messages) - return response.raise_for_status() - except Exception as e: - logger.exception("post_prompt") - raise e \ No newline at end of file diff --git a/src/offical/requests/tongyiqianwen.py b/src/offical/requests/tongyiqianwen.py deleted file mode 100644 index e6ec167..0000000 --- a/src/offical/requests/tongyiqianwen.py +++ /dev/null @@ -1,74 +0,0 @@ -# https://dashscope.console.aliyun.com/model -import asyncio -from concurrent.futures import ThreadPoolExecutor -import json -from typing import Any, AsyncGenerator, AsyncIterator, Generator, Iterator, override -from .remote_engine import RemoteEngine -from src import ExecuteProcessor as ExecuteProcessor - -from logging import getLogger -logger = getLogger(__name__) - -class ChatAiTongYiQianWen(ExecuteProcessor): - API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation" - def __init__(self, api_key : str, - _model : str = "qwen-1.8b-chat", - *args, **kwargs) -> None: - - self._modual_name = kwargs.get("model", _model) - self.use_stream_api=kwargs.get("use_stream_api", False) - self.remote_engine = RemoteEngine(api_key=api_key, - base_url=self.API_URL) - def _transform_raw(self, response): - return response["output"]["choices"][0]["message"]["content"] - - async def _transform_iterator(self, response: AsyncIterator[str]): - current_msg = '' - async for line in response: - if line.startswith("data:"): - current_msg += line[5:].strip() - elif len(line) == 0: - if current_msg: - yield self._transform_raw(json.loads(current_msg)) - current_msg = '' - - async def execute_stream(self, data): - self.remote_engine.header['X-DashScope-SSE'] = 'enable' - response = await self.remote_engine.post_prompt({ - 'model': self._modual_name, - "input": { - "messages": data - }, - "parameters": { - "result_format": "message", - "incremental_output": True - } - }) - return self._transform_iterator(response.aiter_lines()) - - async def execute_nonstream(self, data) -> Any: - response = await self.remote_engine.post_prompt({ - 'model': self._modual_name, - "input": { - "messages": data - }, - "parameters": { - "result_format": "message", - "incremental_output": False - } - }) - ret = response.json() - return self._transform_raw(ret) - - def prepare_input(self, data: Any) -> Any: - return [{'role': 'user', 'content': f'{data}'}] - - @override - async def execute(self, data): - data = self.prepare_input(data) - executor = ThreadPoolExecutor(max_workers=1) - if self.use_stream_api: - res = await self.execute_stream(data) - else: - res = await self.execute_nonstream(data) - return res \ No newline at end of file diff --git a/src/offical/sounds/__init__.py b/src/offical/sounds/__init__.py deleted file mode 100644 index 0332af6..0000000 --- a/src/offical/sounds/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from src import dynamic_package_import -dynamic_package_import([ - ('pyaudio', None), - ]) \ No newline at end of file diff --git a/src/offical/sounds/sounds_play_engine.py b/src/offical/sounds/sounds_play_engine.py deleted file mode 100644 index fcc8d8f..0000000 --- a/src/offical/sounds/sounds_play_engine.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Any, Generator -from src import Engine -import wave -import io -import pyaudio - -from src import StreamEngine - -class SoundsPlayEngine(StreamEngine): - def __init__(self, **kwargs) -> None: - # super().__init__(kwargs.get("is_stream", _is_stream)) - StreamEngine.__init__(self, - use_stream_api=kwargs.get('use_stream_api', False), - return_as_stream=kwargs.get('return_as_stream', False)) - - def execute_nonstream(self, data) -> Any: - if data is None: - return None - wf = wave.open(io.BytesIO(data), 'rb') - _audio = pyaudio.PyAudio() - _stream = _audio.open( - format=_audio.get_format_from_width(wf.getsampwidth()), - channels=wf.getnchannels(), - rate=wf.getframerate(), - output=True) - data = wf.readframes(1024) # 假定块大小为1024 - while data: - _stream.write(data) - data = wf.readframes(1024) - - _stream.stop_stream() - _stream.close() - - _audio.terminate() - wf.close() diff --git a/src/offical/sounds/sounds_record_engine.py b/src/offical/sounds/sounds_record_engine.py deleted file mode 100644 index 8c699b0..0000000 --- a/src/offical/sounds/sounds_record_engine.py +++ /dev/null @@ -1,2 +0,0 @@ -class SoundsRecordEngine: - pass \ No newline at end of file diff --git a/src/offical/sounds/sounds_wrapper.py b/src/offical/sounds/sounds_wrapper.py deleted file mode 100644 index e0a3c77..0000000 --- a/src/offical/sounds/sounds_wrapper.py +++ /dev/null @@ -1,9 +0,0 @@ -import pyaudio - -class SoundsWrapper: - def __init__(self, chunk=1024, format=pyaudio.paInt16, channels=1, rate=44100, input=True, output=True, input_device_index=None, output_device_index=None) -> None: - self.chunk = chunk - self.format = format - self.channels = channels - self.rate = rate - self.input =input \ No newline at end of file diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/plugins/dynamic_package_import.py b/src/plugins/dynamic_package_import.py deleted file mode 100644 index 74ef49f..0000000 --- a/src/plugins/dynamic_package_import.py +++ /dev/null @@ -1,61 +0,0 @@ -r""" -# Example usage -``` -required_packages = [ - ("numpy", "1.20.3"), # Specify version - ("pandas", None), # Latest version -] - -dynamic_package_import(required_packages) -``` -""" - -import importlib.metadata -import subprocess -import sys -from typing import List, Optional, Tuple -import logging -logger = logging.getLogger(__name__) - -def install_or_upgrade_package(package: str, version: Optional[str] = None) -> None: - """ - Installs or upgrades a Python package using pip via Popen. - - :param package: The name of the package to install or upgrade. - :param version: Optional. The version of the package to install. - """ - # Check if the package is already installed - try: - dist = importlib.metadata.distribution(package) - current_version = dist.version - if version and current_version != version: - logger.info(f"Upgrading {package} to version {version}.") - _execute_pip_command(f"install {package}=={version}") - else: - logger.info(f"{package} is already installed at version {current_version}.") - except importlib.metadata.PackageNotFoundError: - logger.info(f"{package} is not installed. Installing...") - _execute_pip_command(f"install {package}{'==' + version if version else ''}") - -def _execute_pip_command(command: str) -> None: - """ - Executes a pip command using subprocess.Popen. - - :param command: The pip command to execute (e.g., 'install numpy'). - """ - pip_cmd = [sys.executable, "-m", "pip", *command.split()] - with subprocess.Popen(pip_cmd, stderr=subprocess.PIPE, universal_newlines=True) as proc: - _, stderr = proc.communicate() - if proc.returncode != 0: - logger.error(f"executing pip command: {command}\n\tdetails: {stderr}") - else: - logger.info(f"Pip command '{command}' executed successfully.") - -def dynamic_package_import(required_packages: List[Tuple[str, Optional[str]]]) -> None: - """ - Checks for the presence of required packages and installs/upgrades them if necessary. - - :param required_packages: A list of tuples, where each tuple contains a package name and optionally a version. - """ - for package, version in required_packages: - install_or_upgrade_package(package, version) \ No newline at end of file diff --git a/src/plugins/plugins.py b/src/plugins/plugins.py deleted file mode 100644 index 66163f6..0000000 --- a/src/plugins/plugins.py +++ /dev/null @@ -1,38 +0,0 @@ -from pathlib import Path -import sys - - -CURRENT_DIR_PATH = Path(__file__).resolve().parent -sys.path.append(str(CURRENT_DIR_PATH.parent.parent.resolve())) -from src import EngineInterface -from .plugins_conf import PluginsConfig -from .plugins_import import PluginsImport - -class Plugins: - def __init__(self, - base_path : Path | str = CURRENT_DIR_PATH, - conf_name : str = ".plugins.yml"): - base_path = Path(base_path) - self.base_path = base_path.resolve() - self.conf_path = base_path / conf_name - - self.config = PluginsConfig.load_config(self.conf_path) - # global_conf: Dict = self.config.get('global') - # self.core_path:Path = self.base_path / (global_conf.get('core_path', '') or '../') - # self.plugin_path:Path = self.base_path / (global_conf.get('plugin_path', '') or './') - # sys.path.append(str(self.base_path)) - - def _get_engine_import(self, engine_name: str): - engine_conf, plg_root_path, plg_path = PluginsConfig.get_engine_conf(engine_name, self.base_path, self.conf_path) - engine_conf.get('plugin_path', '') - plg_import = PluginsImport(plg_root_path) - plg_import.get_module(engine_conf['class_name'], plg_path) - return plg_import, engine_conf - - def load_engine_class(self, engine_name: str): - plg_import, engine_conf = self._get_engine_import(engine_name) - return plg_import.get_class(engine_conf['class_name'], engine_conf['class_name']) - - def load_engine(self, engine_name: str) -> EngineInterface: - plg_import, engine_conf = self._get_engine_import(engine_name) - return plg_import.get_instance(engine_conf['class_name'], engine_conf['class_name'], **engine_conf) \ No newline at end of file diff --git a/src/plugins/plugins_conf.py b/src/plugins/plugins_conf.py deleted file mode 100644 index 1f75312..0000000 --- a/src/plugins/plugins_conf.py +++ /dev/null @@ -1,54 +0,0 @@ -import os -from pathlib import Path - -import re - -from typing import Any, Callable, Dict, Optional, List - -import yaml - -class YamlEnvLoader(yaml.SafeLoader): - def __init__(self, stream): - super(YamlEnvLoader, self).__init__(stream) - self.add_implicit_resolver('!env_var', re.compile(r'\$\{(.+?)\}'), None) - - @staticmethod - def env_var_constructor(loader, node): - value = loader.construct_scalar(node) - match = re.match(r'\$\{(.+?)\}', value) - if match: - env_var = match.group(1) - return os.environ.get(env_var, value) - return value -YamlEnvLoader.add_constructor('!env_var', YamlEnvLoader.env_var_constructor) - -class PluginsConfig: - @staticmethod - def load_config(path: Path) -> Dict[str, Any]: - """Load YAML configuration from the given path.""" - if not path.exists(): - raise FileExistsError(f"{path} not exists") - if not path.is_file(): - raise FileNotFoundError(f"Config file at {path} does not exist.") - with open(path, 'r') as f: - return yaml.load(f, Loader=YamlEnvLoader) - - @staticmethod - def recursive_load(base_path: Path, config: Dict[str, Any] | Any): - """Recursively load configurations when 'plugin' and 'path' are present.""" - if isinstance(config, dict) and 'plugin' in config and 'path' in config: - plugin_path:Path = base_path / config.get('path', '') - nested_config = PluginsConfig.load_config(plugin_path) - config.update(nested_config[config['plugin']]) - plg_root_path = plugin_path.parent / nested_config.get('root_path', None) - if plg_root_path is not None: - plugin_path = plg_root_path / nested_config[config['plugin']]['path'] - return config, plg_root_path, plugin_path - - @staticmethod - def get_engine_conf(engine_name, base_path: Path, config_file: Path): - """ - 获取引擎配置 - """ - conf = PluginsConfig.load_config(config_file) - return PluginsConfig.recursive_load(base_path, conf.get(engine_name)) \ No newline at end of file diff --git a/src/plugins/plugins_import.py b/src/plugins/plugins_import.py deleted file mode 100644 index b077c44..0000000 --- a/src/plugins/plugins_import.py +++ /dev/null @@ -1,48 +0,0 @@ -from pathlib import Path -CURRENT_DIR_PATH = Path(__file__).resolve().parent -import sys -sys.path.append(str(CURRENT_DIR_PATH.parent.parent)) - -import importlib -from types import ModuleType -from typing import Any - -class PluginsImport: - def __init__(self, plugins_path: Path): - plugins_path = plugins_path.parent - if plugins_path not in sys.path: - sys.path.append(str(plugins_path)) - self.plugins_path = plugins_path - self.modules = {} # Store loaded modules here - - def get_module(self, module_name: str, module_path: Path) -> ModuleType: - # Check if the module has already been loaded - if module_name in self.modules: - return self.modules[module_name] - - # Check if the module path is a subpath of the plugins path - if not module_path.is_relative_to(self.plugins_path): - raise ValueError("Module path must be a subpath of the plugins path.") - - relative_path_parts = module_path.relative_to(self.plugins_path).with_suffix('').parts - relative_path = '.'.join(relative_path_parts) - - try: - module = importlib.import_module(relative_path, package=self.plugins_path.name) - self.modules[module_name] = module - return module - except ModuleNotFoundError as e: - raise ModuleNotFoundError(f"Failed to import module '{module_name}' from path '{module_path}': {e}") - - def get_class(self, class_name, module_name) -> Any: - module = self.modules.get(module_name, None) - if module is None: - raise ValueError(f"Module '{module_name}' has not been loaded.") - cls = getattr(module, class_name, None) - if cls is None: - raise AttributeError(f"Class '{class_name}' not found in module '{module_name}'.") - return cls - - def get_instance(self, _class_name, module_name, **kwargs) -> Any: - cls = self.get_class(_class_name, module_name) - return cls(**kwargs) \ No newline at end of file diff --git a/src/pyaudio/sounds_play_engine.py b/src/pyaudio/sounds_play_engine.py new file mode 100644 index 0000000..e771a15 --- /dev/null +++ b/src/pyaudio/sounds_play_engine.py @@ -0,0 +1,23 @@ +from typing import Any, Generator +import wave +import io +import pyaudio + +class SoundsPlayEngine(): + def __init__(self, **kwargs) -> None: + self._player = pyaudio.PyAudio() + self._stream = self._player.open( + format=pyaudio.paInt16, + channels=1, + rate=48000, + output=True) + + + def execute(self, data: bytes, *args) -> Any: + self._stream.write(data) + + # _stream.stop_stream() + # _stream.close() + + # _audio.terminate() + # wf.close() diff --git a/src/utils/logger.py b/src/utils/logger.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/core/__init__.py b/tests/core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/core/test_core.py b/tests/core/test_core.py deleted file mode 100644 index 17ef3cf..0000000 --- a/tests/core/test_core.py +++ /dev/null @@ -1,54 +0,0 @@ -import unittest -from src.core import core - -class TestBaseMiddleware(unittest.TestCase): - def test_process_base_func1(self): - middleware = core.Middleware(lambda x: x + 1) - self.assertEqual(middleware.process(1), 2) - self.assertEqual(middleware.get_next(), []) - - def test_process_base_func2(self): - mid = [core.Middleware(lambda x: x + 2)] - middleware = core.Middleware(lambda x: x + 1, next_middleware=mid) - self.assertEqual(middleware.process(1), 2) - self.assertEqual(middleware._data, 4) - self.assertIs(middleware.get_next(), mid) - -class TestBaseEngine(unittest.TestCase): - pass - -class TestExecutePipeline(unittest.TestCase): - def test_base(self): - middleware = core.Middleware(lambda x: x + 1) - pipeline = core.ExecutePipeline(middleware) - self.assertEqual(pipeline.execute(1), 2) - - def test_add(self): - middleware = core.Middleware(lambda x: x + 1) - pipeline = core.ExecutePipeline(middleware) - pipeline.add(core.Middleware(lambda x: x + 2)) - self.assertEqual(pipeline.execute(1), 4) - - def test_reorder(self): - middleware = core.Middleware(lambda x: x + 1) - pipeline = core.ExecutePipeline(middleware) - pipeline.reorder([]) - pipeline.execute(1) - - def test_reorder1(self): - middleware_p1 = core.Middleware(lambda x: x + 1) - middleware_p2 = core.Middleware(lambda x: x + 2) - middleware_p3 = core.Middleware(lambda x: x + 3) - pipeline = core.ExecutePipeline(middleware_p1, middleware_p2, middleware_p3) - self.assertEqual(pipeline.execute(1), 7) - pipeline.reorder([1, 0, 2]) - self.assertEqual(pipeline.execute(1), 7) - pipeline.reorder([0, 2]) - self.assertEqual(pipeline.execute(1), 6) - pipeline.reorder([1]) - self.assertEqual(pipeline.execute(1), 4) - - def test_execute_none(self): - middleware = core.Middleware(lambda x: x + 1) - pipeline = core.ExecutePipeline(middleware) - self.assertIsNone(pipeline.execute(None)) \ No newline at end of file diff --git a/tests/core/test_echo.py b/tests/core/test_echo.py deleted file mode 100644 index 3978eb7..0000000 --- a/tests/core/test_echo.py +++ /dev/null @@ -1,13 +0,0 @@ -import unittest -from src.core import tools -from io import StringIO -import sys - -class TestEcho(unittest.TestCase): - def test_base(self): - echoMid = tools.EchoMiddleWare() - captured_out = StringIO() - sys.stdout = captured_out - echoMid.process('hello') - sys.stdout = sys.__stdout__ - self.assertEqual(captured_out.getvalue(), 'hello\n') \ No newline at end of file diff --git a/tests/offical/sounds/asr_example.wav b/tests/offical/sounds/asr_example.wav deleted file mode 100644 index a55d567afef6c2ca3630dd4be374e30494bf9a47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128480 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