Compare commits
3 Commits
453c1de0cc
...
f02bb4d3ee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f02bb4d3ee | ||
|
|
17e1a092be | ||
|
|
3e24942d54 |
80
config.py
80
config.py
@ -1,3 +1,83 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class Speaker(Enum):
|
||||||
|
GOOGLE_TEXT_TO_SPEECH = 1
|
||||||
|
STREAMLABS_API = 2
|
||||||
|
|
||||||
|
|
||||||
|
class FileNameStrategy(Enum):
|
||||||
|
TIME_BASED = 1
|
||||||
|
CONTENT_BASED = 2
|
||||||
|
|
||||||
|
|
||||||
|
class PollyVoices(Enum):
|
||||||
|
Aditi = "Aditi"
|
||||||
|
Amy = "Amy"
|
||||||
|
Astrid = "Astrid"
|
||||||
|
Bianca = "Bianca"
|
||||||
|
Brian = "Brian"
|
||||||
|
Camila = "Camila"
|
||||||
|
Carla = "Carla"
|
||||||
|
Carmen = "Carmen"
|
||||||
|
Celine = "Celine"
|
||||||
|
Chantal = "Chantal"
|
||||||
|
Conchita = "Conchita"
|
||||||
|
Cristiano = "Cristiano"
|
||||||
|
Dora = "Dora"
|
||||||
|
Emma = "Emma"
|
||||||
|
Enrique = "Enrique"
|
||||||
|
Ewa = "Ewa"
|
||||||
|
Filiz = "Filiz"
|
||||||
|
Geraint = "Geraint"
|
||||||
|
Giorgio = "Giorgio"
|
||||||
|
Gwyneth = "Gwyneth"
|
||||||
|
Hans = "Hans"
|
||||||
|
Ines = "Ines"
|
||||||
|
Ivy = "Ivy"
|
||||||
|
Jacek = "Jacek"
|
||||||
|
Jan = "Jan"
|
||||||
|
Joanna = "Joanna"
|
||||||
|
Joey = "Joey"
|
||||||
|
Justin = "Justin"
|
||||||
|
Karl = "Karl"
|
||||||
|
Kendra = "Kendra"
|
||||||
|
Kimberly = "Kimberly"
|
||||||
|
Lea = "Lea"
|
||||||
|
Liv = "Liv"
|
||||||
|
Lotte = "Lotte"
|
||||||
|
Lucia = "Lucia"
|
||||||
|
Lupe = "Lupe"
|
||||||
|
Mads = "Mads"
|
||||||
|
Maja = "Maja"
|
||||||
|
Marlene = "Marlene"
|
||||||
|
Mathieu = "Mathieu"
|
||||||
|
Matthew = "Matthew"
|
||||||
|
Maxim = "Maxim"
|
||||||
|
Mia = "Mia"
|
||||||
|
Miguel = "Miguel"
|
||||||
|
Mizuki = "Mizuki"
|
||||||
|
Naja = "Naja"
|
||||||
|
Nicole = "Nicole"
|
||||||
|
Penelope = "Penelope"
|
||||||
|
Raveena = "Raveena"
|
||||||
|
Ricardo = "Ricardo"
|
||||||
|
Ruben = "Ruben"
|
||||||
|
Russell = "Russell"
|
||||||
|
Salli = "Salli"
|
||||||
|
Seoyeon = "Seoyeon"
|
||||||
|
Takumi = "Takumi"
|
||||||
|
Tatyana = "Tatyana"
|
||||||
|
Vicki = "Vicki"
|
||||||
|
Vitoria = "Vitoria"
|
||||||
|
Zeina = "Zeina"
|
||||||
|
Zhiyu = "Zhiyu"
|
||||||
|
|
||||||
|
|
||||||
botList = ("Nightbot", "StreamElements", "Moobot", "praxis_bot")
|
botList = ("Nightbot", "StreamElements", "Moobot", "praxis_bot")
|
||||||
|
|
||||||
slurList = ("fag", "faggot", "niga", "nigga", "nigger", "retard", "tard", "rtard", "coon")
|
slurList = ("fag", "faggot", "niga", "nigga", "nigger", "retard", "tard", "rtard", "coon")
|
||||||
|
|
||||||
|
currentSpeaker = Speaker.STREAMLABS_API
|
||||||
|
fileNameStrategy = FileNameStrategy.CONTENT_BASED
|
||||||
|
streamlabsVoice = PollyVoices.Justin
|
||||||
|
|||||||
@ -5,4 +5,5 @@ SQLAlchemy
|
|||||||
pandas
|
pandas
|
||||||
numpy
|
numpy
|
||||||
gTTS
|
gTTS
|
||||||
playsound
|
playsound
|
||||||
|
pyglet
|
||||||
12
tests/test_tts.py
Normal file
12
tests/test_tts.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
import tts
|
||||||
|
|
||||||
|
class TTSTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_file_name(self):
|
||||||
|
tts.create_file_name("test", "mp3")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@ -4,7 +4,7 @@ import twitch
|
|||||||
|
|
||||||
|
|
||||||
testValidUrls = ['https://shady.ru', 'http://stolencards.zn', 'https://i.imgur.com/FL6slHd.jpg']
|
testValidUrls = ['https://shady.ru', 'http://stolencards.zn', 'https://i.imgur.com/FL6slHd.jpg']
|
||||||
testInvalidUrls = ['this is just a sentence. With a period', 'gotta have some other stuff', 'bad punctuation produces false positives']
|
testInvalidUrls = ['this is just a sentence. With a period', 'gotta have some other stuff', 'bad punctuation.does not produces false positives']
|
||||||
|
|
||||||
|
|
||||||
class TwitchBotTest(unittest.TestCase):
|
class TwitchBotTest(unittest.TestCase):
|
||||||
|
|||||||
82
tts.py
82
tts.py
@ -1,31 +1,89 @@
|
|||||||
|
import datetime
|
||||||
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import datetime
|
import requests
|
||||||
|
from gtts import gTTS
|
||||||
from playsound import playsound
|
from playsound import playsound
|
||||||
|
|
||||||
|
import config
|
||||||
|
|
||||||
|
streamLabsUrl = "https://streamlabs.com/polly/speak"
|
||||||
|
|
||||||
def tts(inputText: str, *args):
|
def tts(inputText: str, *args):
|
||||||
destPath = os.getcwd() + "\\tts\\"
|
outpath = create_speech_file(inputText)
|
||||||
time = datetime.datetime.now()
|
playsound(outpath)
|
||||||
fileName: str = time.strftime("%m-%d-%Y_%H-%M-%S") + "_tts.mp3"
|
|
||||||
|
|
||||||
if len(args) == 1:
|
|
||||||
fileName = args[0] + "_tts.mp3"
|
|
||||||
|
|
||||||
# tts = gTTS(text=inputText, lang='en')
|
def create_speech_gtts(input_text: str):
|
||||||
# tts.save(destPath + fileName)
|
path = os.path.join(get_tts_dir(), create_file_name(input_text, "mp3"))
|
||||||
|
if not os.path.exists(path):
|
||||||
|
sound_digest = gTTS(text=input_text, lang='en')
|
||||||
|
sound_digest.save(path)
|
||||||
|
return path
|
||||||
|
|
||||||
playsound(destPath + fileName)
|
|
||||||
|
|
||||||
# os.system(filename)
|
def create_speech_streamlabs(text: str):
|
||||||
|
path = os.path.join(get_tts_dir(), create_file_name(text, "ogg"))
|
||||||
|
if not os.path.exists(path):
|
||||||
|
body = {"voice": config.streamlabsVoice.value, "text": text}
|
||||||
|
resp = requests.post(streamLabsUrl, data=body).json()
|
||||||
|
sound_file_url = resp["speak_url"]
|
||||||
|
if sound_file_url is not None:
|
||||||
|
sound_bytes = requests.get(sound_file_url, stream=True)
|
||||||
|
f = open(path, "+wb")
|
||||||
|
f.write(sound_bytes.content)
|
||||||
|
f.close()
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
speechCreationFunctions = { # this is a mapping of the Speaker enum to function pointers
|
||||||
|
config.Speaker.STREAMLABS_API: create_speech_streamlabs,
|
||||||
|
config.Speaker.GOOGLE_TEXT_TO_SPEECH: create_speech_gtts
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def create_speech_file(text: str):
|
||||||
|
text_creation_function = speechCreationFunctions.get(config.currentSpeaker)
|
||||||
|
output_path = text_creation_function(text)
|
||||||
|
return output_path
|
||||||
|
|
||||||
|
|
||||||
|
def create_file_name(text: str, ext: str):
|
||||||
|
"""
|
||||||
|
:param text: the content of the message. using the CONTENT_BASED FileNameStrategy, this will (ostensibly) produce a
|
||||||
|
unique file name based on the content of the message. Two messages of equal content will produce the same name
|
||||||
|
:param ext: the desired file extension i.e. mp3, ogg, wav, etc...
|
||||||
|
:return: returns the formatted filename i.e. 01-01-20_01-01-01_tts.mp3
|
||||||
|
"""
|
||||||
|
if config.fileNameStrategy == config.FileNameStrategy.CONTENT_BASED:
|
||||||
|
unique_id = hashlib.md5(bytes(text, 'utf-8')).hexdigest()
|
||||||
|
return "%s_tts.%s" % (unique_id, ext)
|
||||||
|
|
||||||
|
elif config.fileNameStrategy == config.FileNameStrategy.CONTENT_BASED:
|
||||||
|
time = datetime.datetime.now()
|
||||||
|
return "%s_tts.%s" % (time.strftime("%m-%d-%Y_%H-%M-%S"), ext)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return "unconfigured_tts.%s" % ext
|
||||||
|
|
||||||
|
|
||||||
def play_speech(fileName):
|
def play_speech(fileName):
|
||||||
destPath = os.getcwd() + "\\tts\\"
|
destPath = get_tts_dir()
|
||||||
playsound(destPath + fileName)
|
playsound(destPath + fileName)
|
||||||
|
|
||||||
|
|
||||||
|
def get_tts_dir():
|
||||||
|
"""
|
||||||
|
Checks for the tts directory, and will create it if it does not exist
|
||||||
|
:return: the relative file path of the tts dir
|
||||||
|
"""
|
||||||
|
dir = os.path.join(os.getcwd(), "tts") # this is platform-agnostic
|
||||||
|
if not os.path.exists(dir):
|
||||||
|
os.mkdir(dir)
|
||||||
|
return dir
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Enter Text: ")
|
print("Enter Text: ")
|
||||||
textInput = str(input())
|
textInput = str(input())
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import random
|
import random
|
||||||
|
import re
|
||||||
|
|
||||||
import twitch
|
import twitch
|
||||||
import twitch.chat
|
import twitch.chat
|
||||||
import twitch_cred as twitch_credentials
|
|
||||||
|
|
||||||
import config as config
|
import config as config
|
||||||
import tts
|
|
||||||
|
|
||||||
import db
|
import db
|
||||||
import re
|
import tts
|
||||||
|
import twitch_cred as twitch_credentials
|
||||||
|
|
||||||
|
|
||||||
class Twitch_Module():
|
class Twitch_Module():
|
||||||
@ -19,7 +19,8 @@ class Twitch_Module():
|
|||||||
self.links_allowed: bool = True
|
self.links_allowed: bool = True
|
||||||
self.whitelisted_users: list = ["thecuriousnerd", "theredpoint", "lakotor"]
|
self.whitelisted_users: list = ["thecuriousnerd", "theredpoint", "lakotor"]
|
||||||
# don't freak out, this is *merely* a regex for matching urls that will hit just about everything
|
# don't freak out, this is *merely* a regex for matching urls that will hit just about everything
|
||||||
self._urlMatcher = re.compile("(https?:(/{1,3}|[a-z0-9%])|[a-z0-9.-]+[.](com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw))")
|
self._urlMatcher = re.compile(
|
||||||
|
"(https?:(/{1,3}|[a-z0-9%])|[a-z0-9.-]+[.](com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw))")
|
||||||
|
|
||||||
def join_channel(self, channel_name):
|
def join_channel(self, channel_name):
|
||||||
channel_name = "#" + channel_name
|
channel_name = "#" + channel_name
|
||||||
@ -81,31 +82,19 @@ class Twitch_Module():
|
|||||||
print("{something went wrong}")
|
print("{something went wrong}")
|
||||||
|
|
||||||
def tts_message(self, message: twitch.chat.Message):
|
def tts_message(self, message: twitch.chat.Message):
|
||||||
if self.contains_slur(message) == False:
|
if not self.contains_slur(message):
|
||||||
if self.tts_enabled == True:
|
if self.tts_enabled:
|
||||||
if message.text.startswith('!') == False:
|
if not message.text.startswith('!'):
|
||||||
|
text_to_say: str = "%s says, %s" % (message.sender, message.text)
|
||||||
|
channel_text = "%s user msg" % message.channel
|
||||||
|
|
||||||
if message.sender.lower() == message.channel:
|
if message.sender.lower() == message.channel:
|
||||||
tts.tts(message.sender + " says, " + message.text)
|
tts.tts(text_to_say)
|
||||||
else:
|
else:
|
||||||
# tts.tts(message.sender + " says, " + message.text)
|
# tts.tts(message.sender + " says, " + message.text)
|
||||||
tts.tts(message.sender + " says, " + message.text, message.channel + " user msg")
|
tts.tts(text_to_say, channel_text)
|
||||||
|
|
||||||
def contains_url(self, message: twitch.chat.Message):
|
def contains_url(self, message: twitch.chat.Message):
|
||||||
# containsURL: bool = False
|
|
||||||
# if message.text.lower().find("http") != -1:
|
|
||||||
# containsURL = True
|
|
||||||
# if message.text.lower().find("https") != -1:
|
|
||||||
# containsURL = True
|
|
||||||
# if message.text.lower().find(".com") != -1:
|
|
||||||
# containsURL = True
|
|
||||||
# if message.text.lower().find(".net") != -1:
|
|
||||||
# containsURL = True
|
|
||||||
# if message.text.lower().find(".org") != -1:
|
|
||||||
# containsURL = True
|
|
||||||
# if message.text.lower().find(".tv") != -1:
|
|
||||||
# containsURL = True
|
|
||||||
# if message.text.lower().find(".io") != -1:
|
|
||||||
# containsURL = True
|
|
||||||
containsURL = re.search(self._urlMatcher, message.text.lower()) is not None
|
containsURL = re.search(self._urlMatcher, message.text.lower()) is not None
|
||||||
if containsURL:
|
if containsURL:
|
||||||
print("<{ link detected! }> " + " [#" + message.channel + "](" + message.sender + ") sent a link in chat")
|
print("<{ link detected! }> " + " [#" + message.channel + "](" + message.sender + ") sent a link in chat")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user