Files
conjurer/voice_recognition.py
T
2024-09-17 21:48:30 +02:00

107 lines
3.8 KiB
Python

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()
# URL of the file to transcribe
FILE_URL = "https://github.com/AssemblyAI-Community/audio-examples/raw/main/20230607_me_canadian_wildfires.mp3"
# You can also transcribe a local file by passing in a file path
# FILE_URL = './path/to/file.mp3'
logger = logging.getLogger("discord")
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):
def __init__(self, bot):
def callback(user, data: voice_recv.VoiceData):
logger.info(f"Got packet from {user}")
self.bot = bot
self._last_member = None
self.wsink = voice_recv.SRBuffer(destination="/home/pi/Conjurer/wav.wav")
async def transcribe():
config = aai.TranscriptionConfig(speaker_labels=True)
transcriber = aai.Transcriber()
transcript = transcriber.transcribe(
FILE_URL,
config=config
)
for utterance in transcript.utterances:
print(f"Speaker {utterance.speaker}: {utterance.text}")
@commands.hybrid_command(name="transcribe")
async def test(self, ctx):
logger.info("Attempt transcribe")
vc = await ctx.author.voice.channel.connect(cls=voice_recv.VoiceRecvClient)
logger.info("Connected")
vc.listen(self.wsink)
@commands.command(name="stop_transcribe")
async def stop(self, ctx):
await ctx.voice_client.disconnect()
async def setup(bot):
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.