From acc59de61b08176c24ce1d36473c6223e2f240f0 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Thu, 6 Oct 2022 18:12:01 +0300 Subject: [PATCH] Class done - need test / fix silent mode and callback --- Sources/pyOpenRPA/Robot/Audio.py | 101 ++++++++++++++++---- Tools/Jupyter-notebooks/Audio.ipynb | 112 ++++++++++++++++++++--- Tools/Jupyter-notebooks/KPI_Effect.ipynb | 86 +++++++++++++++++ 3 files changed, 266 insertions(+), 33 deletions(-) create mode 100644 Tools/Jupyter-notebooks/KPI_Effect.ipynb diff --git a/Sources/pyOpenRPA/Robot/Audio.py b/Sources/pyOpenRPA/Robot/Audio.py index 5e6c863f..b8e9871d 100644 --- a/Sources/pyOpenRPA/Robot/Audio.py +++ b/Sources/pyOpenRPA/Robot/Audio.py @@ -5,6 +5,9 @@ import threading import wave import time from pyOpenRPA.Utils import Text +import os + + def DeviceMicrophoneIndex(): @@ -34,7 +37,9 @@ def DeviceSystemSoundIndex(): elif inIsLoopbackBool==False: lCompareBool = True if lCompareBool == True: lDiffRationFloat = Text.SimilarityNoCase(in1Str=lDefaultNameStr, in2Str=lItemDict["NameStr"]) - if lDiffRationFloat> lCatchDiffRatioFloat: lCatchIndexInt=lItemDict["IndexInt"] + if lDiffRationFloat> lCatchDiffRatioFloat: + lCatchDiffRatioFloat = lDiffRationFloat + lCatchIndexInt=lItemDict["IndexInt"] else: lDeviceInfoDict = p.get_default_output_device_info() lDefaultIndexInt = lDeviceInfoDict["index"] @@ -81,8 +86,8 @@ def DeviceListGet(): return l_result class Recorder: - - mStatusStr = "0_READY" + mT=[] + mStatusStr = "0_READY" # "0_READY", "1_RECORDING" mAudio = None mCaptureThread = None mStream = None @@ -91,21 +96,50 @@ class Recorder: mChannelCountInt = None mFramesInt = 512 mRecordedFramesList = [] - mUseLoopbackBool = True mSampleRateInt = None mSampleSizeInt = None mCaptureBool = True - mFilePathStr = "out" - mFileFormatStr = "mp3" - + mFolderPathStr = None + mFileNameStr = None + mFileFormatStr = None + mFileAvailableChunkInt = None + mFileNameList=None + + mChunkSecFloat = None + mChunkSilentSecFloat = None + + mStartSecFloat = None + mStartChunkSecFloat = None + mDurationSecFloat = None + mThresholdInt = 500 + + mSilentLastCheckTimeFloat = None + + mIsMicrophoneBool=None def __init__(self, inDeviceInt=None): self.mDeviceInt = inDeviceInt - if inDeviceInt == None: self.mDeviceInt = DeviceSystemSoundIndex() + if inDeviceInt == None: inDeviceInt = DeviceSystemSoundIndex() + self.mDeviceInt = inDeviceInt + if DeviceListGet()[inDeviceInt]["MaxInputChannelsInt"]>0: self.mIsMicrophoneBool = True + else: self.mIsMicrophoneBool = False - def CaptureStart(self, inFilePathStr = "out", inFileFormatStr = "mp3", inDoChunkBool = False): - self.mFilePathStr = inFilePathStr + def StatusGet(self): + return self.mStatusStr + + def CaptureStart(self, inFolderPathStr="",inFileNameStr = "out", inFileFormatStr = "mp3", inDurationSecFloat = None, inChunkSecFloat = 300.0, inChunkSilentSecFloat = 10.0): + # CHECK AUX.mp3 + self.mFileNameList=[] + self.mRecordedFramesList=[] + self.mStatusStr = "1_RECORDING" + if inChunkSecFloat != None or inChunkSilentSecFloat != None: self.mFileAvailableChunkInt = 0 + self.mDurationSecFloat = inDurationSecFloat + self.mChunkSecFloat = inChunkSecFloat + self.mChunkSilentSecFloat = inChunkSilentSecFloat + self.mSilentLastCheckTimeFloat=time.time() + self.mFolderPathStr = inFolderPathStr + self.mFileNameStr = inFileNameStr self.mFileFormatStr = inFileFormatStr self.mAudio = pyaudio.PyAudio() self.mSampleSizeInt = self.mAudio.get_sample_size(pyaudio.paInt16) @@ -119,24 +153,32 @@ class Recorder: input = True, frames_per_buffer = self.mFramesInt, input_device_index = lDeviceInfoDict["index"], - as_loopback = self.mUseLoopbackBool) + as_loopback = not self.mIsMicrophoneBool) self.mCaptureThread = threading.Thread(target=self.__Capture__) + self.mStartSecFloat = time.time() + self.mStartChunkSecFloat = self.mStartSecFloat self.mCaptureThread.start() def __Capture__(self): while self.mCaptureBool==True: self.mRecordedFramesList.append(self.mStream.read(self.mFramesInt)) + self.__TriggerCheck__() + + def CaptureStop(self, inWaitStream=True): + self.mCaptureBool=False + if inWaitStream == True: self.mCaptureThread.join() self.mStream.stop_stream() self.mStream.close() #Close module self.mAudio.terminate() - - def CaptureStop(self): - self.mCaptureBool=False - self.mCaptureThread.join() self.CaptureChunk() + self.mStatusStr = "0_READY" def CaptureChunk(self): + lFileNameStr = self.mFileNameStr + if self.mFileAvailableChunkInt!=None: + lFileNameStr+=f"_{self.mFileAvailableChunkInt:05}" + self.mFileAvailableChunkInt = self.mFileAvailableChunkInt + 1 # Advanced usage, if you have raw audio data: sound = AudioSegment( # raw audio data (bytes) @@ -148,13 +190,16 @@ class Recorder: # stereo channels=self.mChannelCountInt ) - sound.export(f"{self.mFilePathStr}.{self.mFileFormatStr}", format=f"{self.mFileFormatStr}") + sound.export(os.path.join(self.mFolderPathStr,f"{lFileNameStr}.{self.mFileFormatStr}"), format=f"{self.mFileFormatStr}") + self.mFileNameList.append(f"{lFileNameStr}.{self.mFileFormatStr}") self.mRecordedFramesList = [] + self.mStartChunkSecFloat = time.time() def FileListGet(self): - pass + return self.mFileNameList + def FileLastGet(self): - pass + return self.mFileNameList[-1] def __Callback__(self, inDefList): pass @@ -165,11 +210,27 @@ class Recorder: def __CallbackIsStopped__(self): pass - def __TriggerCenter__(self): + def IsSilent(self, inLastSecFloat=None): + "Returns 'True' if below the 'silent' threshold" + self.mSilentLastCheckTimeFloat = time.time() + if inLastSecFloat == None: inLastSecFloat = self.mChunkSilentSecFloat + lFrameLenInt = int(self.mSampleSizeInt*inLastSecFloat) + if lFrameLenInt self.mChunkSecFloat: self.CaptureChunk() + # Остановка записи по максимальной длине + if self.mDurationSecFloat != None and time.time() - self.mStartSecFloat > self.mDurationSecFloat: self.CaptureStop(inWaitStream=False) + # Проверка тишины + #if self.mChunkSilentSecFloat != None and time.time() - self.mSilentLastCheckTimeFloat and self.IsSilent(): self.mT.append("ТИШИНА!!") + + diff --git a/Tools/Jupyter-notebooks/Audio.ipynb b/Tools/Jupyter-notebooks/Audio.ipynb index ead710db..803c8a57 100644 --- a/Tools/Jupyter-notebooks/Audio.ipynb +++ b/Tools/Jupyter-notebooks/Audio.ipynb @@ -15,25 +15,40 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "metadata": {}, "outputs": [ { - "ename": "AttributeError", - "evalue": "'Recorder' object has no attribute 'test'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mpyOpenRPA\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mRobot\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mAudio\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mlRec\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAudio\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mRecorder\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minDeviceInt\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mlRec\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtest\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mAttributeError\u001b[0m: 'Recorder' object has no attribute 'test'" + "name": "stdout", + "output_type": "stream", + "text": [ + "2 - NEC LCD1703M (AMD High Definition Audio Device): 0.2926829268292683 _ 0.0\n", + "Динамики (USB PnP Sound Device): 0.7419354838709677 _ 0.2926829268292683\n", + "Динамики (Realtek High Definition Audio): 0.22535211267605634 _ 0.7419354838709677\n", + "9\n" ] + }, + { + "data": { + "text/plain": [ + "{'IndexInt': 9,\n", + " 'NameStr': 'Динамики (USB PnP Sound Device)',\n", + " 'MaxInputChannelsInt': 0,\n", + " 'MaxOutputChannelsInt': 2,\n", + " 'HostApiInt': 1,\n", + " 'DefaultSampleRateFloat': 44100.0,\n", + " 'HostApiStr': 'Windows WASAPI'}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "from pyOpenRPA.Robot import Audio\n", - "lRec = Audio.Recorder(inDeviceInt=10)\n", - "lRec.test()" + "print(Audio.DeviceSystemSoundIndex())\n", + "Audio.DeviceListGet()[9]" ] }, { @@ -43,8 +58,39 @@ "outputs": [], "source": [ "from pyOpenRPA.Robot import Audio\n", - "lRec = Audio.Recorder(inDeviceInt=10)\n", - "lRec.CaptureStart()" + "lRec = Audio.Recorder(inDeviceInt = Audio.DeviceMicrophoneIndex())\n", + "lRec.CaptureStart(inFileNameStr = \"out2\", inFileFormatStr = \"mp3\", inDurationSecFloat = None, inChunkSecFloat = 15.0, inChunkSilentSecFloat = 3.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from pyOpenRPA.Robot import Audio\n", + "lRec = Audio.Recorder()\n", + "lRec.CaptureStart(inFileNameStr = \"out\", inFileFormatStr = \"mp3\", inDurationSecFloat = None, inChunkSecFloat = 5.0, inChunkSilentSecFloat = 10.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lRec.FileListGet()" ] }, { @@ -56,6 +102,46 @@ "lRec.CaptureStop()" ] }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lRec.mT" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'1_RECORDING'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lRec.StatusGet()" + ] + }, { "cell_type": "code", "execution_count": 10, diff --git a/Tools/Jupyter-notebooks/KPI_Effect.ipynb b/Tools/Jupyter-notebooks/KPI_Effect.ipynb new file mode 100644 index 00000000..33035ba0 --- /dev/null +++ b/Tools/Jupyter-notebooks/KPI_Effect.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "sys.path.insert(0, os.path.abspath(\"..\\\\..\\\\Sources\"))\n", + "sys.path.insert(0, os.path.abspath(\"..\\\\..\\\\..\\\\KPI_Effect\\\\packages\"))\n", + "import time\n", + "import kpi_client\n", + "kpi_client.init(\"http://localhost:1024\", \"1992-04-03-0643-ru-b4ff-openrpa52zzz\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "l_start_float = time.time()-200\n", + "kpi_client.log(in_code_str=\"Zzz\",in_group_str=\"БУХГАЛТЕР - ПЛАТЕЖНЫЕ поручения 2\",in_manual_operation_float=300, in_auto_operation_float=200, in_start_time_float=l_start_float)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.2" + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}