diff --git a/bot.py b/bot.py index 1e14598..711fac0 100644 --- a/bot.py +++ b/bot.py @@ -122,7 +122,6 @@ class MusicFileList(object): # *=========================================== Predefines -formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") MASTER_TIMEOUT = datetime.now() INITIAL_TIME_WAIT = 500 MUZYKA: Music_Config = {"ctx": None, "queue": [], "requester": []} @@ -243,6 +242,7 @@ handler = handlers.RotatingFileHandler( maxBytes=6 * 1024 * 1024, backupCount=6, ) +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") handler.setFormatter(formatter) logger.addHandler(handler) random.seed() diff --git a/requirements_bot.txt b/requirements_bot.txt index 9c7deaa..dd2fcd4 100644 --- a/requirements_bot.txt +++ b/requirements_bot.txt @@ -15,4 +15,5 @@ flask waitress clickupython assemblyai[extras] +SpeechRecognition git+https://github.com/imayhaveborkedit/discord-ext-voice-recv \ No newline at end of file diff --git a/voice_recognition.py b/voice_recognition.py index 3907912..b203d08 100644 --- a/voice_recognition.py +++ b/voice_recognition.py @@ -1,13 +1,10 @@ -# Start by making sure the `assemblyai` package is installed. -# If not, you can install it by running the following command: -# pip install -U assemblyai -# -# Note: Some macOS users may need to use `pip3` instead of `pip`. - import assemblyai as aai import discord from discord.ext import commands, voice_recv import logging +from discord.opus import Decoder as OpusDecoder +import wave + # Replace with your API key aai.settings.api_key = "aa9962f0088a449a9c4ab2361e96cc08" discord.opus._load_default() @@ -20,28 +17,55 @@ FILE_URL = "https://github.com/AssemblyAI-Community/audio-examples/raw/main/2023 logger = logging.getLogger("discord") -''' -class SRAudioSinkHammerVersion(AudioSink): - def __init__( - self, - *, - process_cb: Optional[SRProcessDataCB] = None, - text_cb: Optional[SRTextCB] = None, - default_recognizer: SRRecognizerMethod = 'google', - phrase_time_limit: int = 10, - ignore_silence_packets: bool = True, - ): - super().__init__(None) - self.process_cb: Optional[SRProcessDataCB] = process_cb - self.text_cb: Optional[SRTextCB] = text_cb - self.phrase_time_limmit: int = phrase_time_limit - self.ignore_silence_packets: bool = ignore_silence_packets - self.default_recognizer: SRRecognizerMethod = default_recognizer - self._stream_data: defaultdict[int, _StreamData] = defaultdict( - lambda: _StreamData(stopper=None, recognizer=sr.Recognizer(), buffer=array.array('B')) - ) -''' +class SRBuffer(voice_recv.AudioSink): + """Endpoint AudioSink that generates a wav file. + Best used in conjunction with a silence generating sink. (TBD) + """ + + CHANNELS = OpusDecoder.CHANNELS + SAMPLE_WIDTH = OpusDecoder.SAMPLE_SIZE // OpusDecoder.CHANNELS + SAMPLING_RATE = OpusDecoder.SAMPLING_RATE + + ##on member join - 5 plików buforowych na człowieka otwarty jest tylko aktualny i następny + #on member disconnect - dropujemy go + + + # event: BasicSinkWriteCB, + # rtcp_event: Optional[BasicSinkWriteRTCPCB] = None, + # self.cb = event + # self.cb_rtcp = rtcp_event + # def write(self, user: Optional[User], data: VoiceData) -> None: + # self.cb(user, data) + # @AudioSink.listener() + # def on_rtcp_packet(self, packet: RTCPPacket, guild: discord.Guild) -> None: + # self.cb_rtcp(packet) if self.cb_rtcp else None + + + + def __init__(self, destination: wave._File): + super().__init__() + + self._file: wave.Wave_write = wave.open(destination, 'wb') + self._file.setnchannels(self.CHANNELS) + self._file.setsampwidth(self.SAMPLE_WIDTH) + self._file.setframerate(self.SAMPLING_RATE) + self.user_list = [] + + def wants_opus(self) -> bool: + return False + + def write(self, user, data) -> None: + logger.info("writing to file %s", self._file) + logger.info("user: %s", user) + self._file.writeframes(data.pcm) + + def cleanup(self) -> None: + try: + self._file.close() + except Exception: + logger.warning("WaveSink got error closing file on cleanup", exc_info=True) + class Transcriber(commands.Cog): @@ -51,10 +75,7 @@ class Transcriber(commands.Cog): self.bot = bot self._last_member = None - bsink = voice_recv.BasicSink(callback) - wsink = voice_recv.WaveSink(destination="/home/pi/Conjurer/wav.wav") - fsink = voice_recv.FFmpegSink(filename = ".home/pi/Conjurer/mp3.mp3") - self.sink_list = [bsink, wsink, fsink] + self.wsink = voice_recv.SRBuffer(destination="/home/pi/Conjurer/wav.wav") async def transcribe(): config = aai.TranscriptionConfig(speaker_labels=True) @@ -71,8 +92,7 @@ class Transcriber(commands.Cog): logger.info("Attempt transcribe") vc = await ctx.author.voice.channel.connect(cls=voice_recv.VoiceRecvClient) logger.info("Connected") - msink = voice_recv.MultiAudioSink(destinations= self.sink_list) - vc.listen(msink) + vc.listen(self.wsink) @commands.command(name="stop_transcribe") @@ -80,4 +100,8 @@ class Transcriber(commands.Cog): await ctx.voice_client.disconnect() async def setup(bot): - await bot.add_cog(Transcriber(bot)) \ No newline at end of file + await bot.add_cog(Transcriber(bot)) + + +#1. zapisuj kwestie człowieka do pliku w którym będzie można stwierdzić kto co powiedział (callback z basicaudio + write z wavesinka). Zamykaj plik i wysyłaj do transkrypcji w momencie ciszy dłuższej niż 0.5s. Jeśli człowiek nadaje cały czas dawaj sygnał że nie można go transkrybować - i wyłaczaj zapis. +#2. Transkrypcja to abstrakt - w zależności od tego która metoda jest włączona wysyła do odpowiedniego silnika, silniki offline odpalam na activcomie. Zaczynamy od assemblyai bo najlepiej wspiera polski. Potem zobaczymy co dalej. \ No newline at end of file