Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Bool options #17

Merged
merged 3 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions app/middlewares/option_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def pre_process(self, message, data):
if isinstance(message, InlineQuery):
msg_text = message.query
if msg_text == "":
msg_text = "*"
msg_text = "placeholder"
if msg_text[0] == '/':
options = msg_text.split(" ",1)
options.pop(0)
Expand All @@ -26,12 +26,33 @@ def pre_process(self, message, data):
options = msg_text.split(" ",1)
options.pop(0)

opt_data = dict({"bool_options": False,
"options":[]})
if options:
# remove spaces and make options list
options = options[0].replace(" ","")
options = options.split(",")
# takes the option string
opt_str = options[0]
try:
# if user input options are in binary
opt = bin(int(opt_str, 2))[2:]
except ValueError:
try:
# if user input options are in hex
opt = bin(int(opt_str,16))[2:]
except ValueError:
# if it's in plain string
opt = opt_str
# build binary array and not too long
if opt.isdigit():
# the last 16 options
opt = opt[-16:]
# set the flag to true
opt_data["bool_options"] = True
for i in opt.zfill(16):
opt_data["options"].append(bool(int(i)))
else:
opt_data["options"].append(opt)

data['options'] = options
data["options"] = opt_data

def post_process(self, message, data, exception=None):
pass
40 changes: 20 additions & 20 deletions app/models/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ class Audio(Base):
VOLUME_HIGH = 0.6
VOLUME_LOW = 0.3

OPTIONS_AVAILABLE = ['sine', 'noise']
# s: sine; n: noise
OPTIONS_AVAILABLE = ['s', 'n']
OPTIONS_DEFAULT = {
"sine": True,
"noise": False
"s":{"enabled": True},
"n":{"enabled": False}
}

# generate a noise sample
Expand All @@ -51,7 +52,7 @@ def sine_sample(freq, volume, x):
def _mix_up(self, len):
values = []
for i in range(0, len):
if self._options['sine']:
if self._options['s']["enabled"]:
# two channels
freq_channel_1 = random.randint(Audio.FREQ_LOW, Audio.FREQ_HIGH)
freq_channel_2 = random.randint(Audio.FREQ_LOW, Audio.FREQ_HIGH)
Expand All @@ -62,21 +63,21 @@ def _mix_up(self, len):
# duration of every chunk
chunk_duration = random.randint(1, 3)
for x in range(0, chunk_duration * Audio.SAMPLE_RATE):
if self._options['sine']:
if self._options['s']["enabled"]:
sine_channel_1 = Audio.sine_sample(freq_channel_1, volume_channel_1, x)
sine_channel_2 = Audio.sine_sample(freq_channel_2, volume_channel_2, x)
if self._options['noise']:
if self._options['n']["enabled"]:
noise_channel_1 = Audio.noise_sample()
noise_channel_2 = Audio.noise_sample()

# build into values
if self._options['sine'] and self._options['noise']:
if self._options['s']["enabled"] and self._options['n']["enabled"]:
values.append(random.choice([sine_channel_1, noise_channel_1]))
values.append(random.choice([sine_channel_2, noise_channel_2]))
elif self._options['sine'] and not self._options['noise']:
elif self._options['s']["enabled"] and not self._options['n']["enabled"]:
values.append(sine_channel_1)
values.append(sine_channel_2)
elif self._options['noise'] and not self._options['sine']:
elif self._options['n']["enabled"] and not self._options['s']["enabled"]:
values.append(noise_channel_1)
values.append(noise_channel_2)

Expand All @@ -88,21 +89,20 @@ def _mix_up(self, len):
def generate(self, options=None):
name = uuid.uuid4().hex
# add prefix to file name
name_prefix = "/sine-"
name_prefix = "/"
# set options
self._options = dict(Audio.OPTIONS_DEFAULT)
if options and not options == ['']:
name_prefix = "/"
self._options = dict.fromkeys(Audio.OPTIONS_AVAILABLE, False)
for option in options:
if option in Audio.OPTIONS_AVAILABLE:
self._options[option] = True
name_prefix = name_prefix + option + "-"
if options:
self.set_options(options)

# apply options to filename
for i in self._options:
if self._options[i]["enabled"]:
name_prefix = name_prefix + i + "-"

# if options are empty now, return to default
if self._options == dict.fromkeys(Audio.OPTIONS_AVAILABLE, False):
if self._options == dict.fromkeys(Audio.OPTIONS_AVAILABLE, {"enabled":False}):
self._options = dict(Audio.OPTIONS_DEFAULT)
name_prefix += "sine-"
name_prefix = "/s-"

self._filename = name_prefix+name+".wav"
self._filepath = dirs.AUDIO_DIR+self._filename
Expand Down
21 changes: 21 additions & 0 deletions app/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@
base.py
the Base model
"""
import copy

from telebot import TeleBot
from telebot.types import Message

class Base:

OPTIONS_AVAILABLE = []
OPTIONS_DEFAULT = {}

def __init__(self,
bot:TeleBot = None,
message:Message = None):
self.__bot = bot
self.__message = message
self._options = copy.deepcopy(self.OPTIONS_DEFAULT)


# get content of this object
Expand All @@ -23,6 +28,22 @@ def content(self):
def set_content(self, content:str):
self._content = content

# set options
def set_options(self, options):
if options["bool_options"]:
opt = options["options"]
# index for mapping from boolean array to options
index = 0
for i in self._options:
# change options accordingly, opt with be chopped to the last elements
self._options[i]["enabled"] = opt[-len(self.OPTIONS_AVAILABLE):][index]
index += 1
else:
# TODO: support non-bool options
pass

return self

# generate content
def generate(self):
raise NotImplementedError
Expand Down
80 changes: 25 additions & 55 deletions app/models/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,67 +20,37 @@ class Text(Base):
'<', '>', '#', '+',
'-', '=', '|', '{',
'}', '.', '!']

OPTIONS_AVAILABLE = ['en', 'zh', 'punc','d']

# Stands for zh, english, punctuations, digits, must be in order
OPTIONS_AVAILABLE = ['z', 'e', 'p','d']
# Default: 0111
OPTIONS_DEFAULT = {
"en": True,
"zh": False,
"punc": True,
"d": True,
"z":{"enabled": False,
"content": lambda zh:[zh+chr(random.randint(0x4e00,0xa000)) for i in range(0,30)]},
"e":{"enabled": True,
"content": string.ascii_letters},
"p":{"enabled": True,
"content": string.punctuation},
"d":{"enabled": True,
"content": string.digits}
}

# generate random string, returns the object itself
def generate(self, options = None):

# set default options
self._options = dict(Text.OPTIONS_DEFAULT)
# check options
if options:
self.set_options(options)

# if option not nothing
if options and not options == ['']:
option_bodies = []
# check each option in options
for option in options:
# if the option is empty, we see it as setting all others false
if option == '':
for i in Text.OPTIONS_AVAILABLE:
if i not in option_bodies:
self._options[i] = False
# if the option is not empty
else:
# get option body without "+" or "-"
if option[0] == "+" or option[0] == "-":
option_body = option.replace(option[0],"",1)
option_bodies.append(option_body)
else:
# if option has no operator, it is "+"
option_body = option
option_bodies.append(option_body)
if option_body in Text.OPTIONS_AVAILABLE:
if option[0] == '-':
self._options[option_body] = False
else:
self._options[option_body] = True

# make choice string
# build the choices string
choices_string = ""

# add strings for each options
if self._options["en"]:
choices_string += string.ascii_letters

if self._options["zh"]:
zh_string = ""
# generate a Chinese string of 30 chars
for i in range(0,30):
zh_string += chr(random.randint(0x4e00, 0xa000))
choices_string += zh_string

if self._options["punc"]:
choices_string += string.punctuation

if self._options["d"]:
choices_string += string.digits

for i in self._options:
if self._options[i]["enabled"]:
# if the content is a function
if callable(self._options[i]["content"]):
choices_string += "".join(self._options[i]["content"](""))
else:
choices_string += "".join(self._options[i]["content"])

# if the string is empty, return random *s
if not choices_string:
choices_string = "*"
Expand All @@ -94,7 +64,7 @@ def generate(self, options = None):
# convert to mono for markdown parsing
def to_mono(self):
# if there is no puncs, no need to check
if self._options['punc']:
if self._options["p"]["enabled"]:
# add a "\" before every special char
for i in Text.SPECIAL:
self._content = self._content.replace(i,"\\"+i)
Expand Down
10 changes: 3 additions & 7 deletions tests/audio_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,15 @@ def test_audio_generated():

def test_audio_noise():
audio = Audio()
assert isinstance(audio.generate(options = ['noise']), Audio)
assert isinstance(audio.generate(options = {"bool_options": True, "options":[False,True]}), Audio)

def test_audio_mix():
audio = Audio()
assert isinstance(audio.generate(options = ['noise', 'sine']), Audio)

def test_audio_wrong_options():
audio = Audio()
assert isinstance(audio.generate(options = ['aa']), Audio)
assert isinstance(audio.generate(options = {"bool_options": True, "options":[True,True]}), Audio)

def test_audio_empty_options():
audio = Audio()
assert isinstance(audio.generate(options = ['']), Audio)
assert isinstance(audio.generate(options = {"bool_options": False, "options": "aa"}), Audio)

def test_audio_to_mpeg():
audio = Audio()
Expand Down
10 changes: 5 additions & 5 deletions tests/text_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ def test_text_generated():

def test_text_options():
text = Text()
text.generate(options = ['zh','+en', '-d'])
text.generate(options = {"bool_options":True, "options":[True, True, True, False]})
assert isinstance(text.content(),str)

def test_text_option_only():
text = Text()
text.generate(options = ['en', ''])
assert isinstance(text.content(),str) and text.content().isascii()
text.generate(options = {"bool_options":True, "options":[False, False, False, True]})
assert isinstance(text.content(),str) and text.content().isdigit()

def test_text_wrong_options():
text = Text()
text.generate(options = ['aaa'])
text.generate(options = {"bool_options": True, "options":[True,False,True,False,False]})
assert isinstance(text.content(),str) and text.content().isascii()

def test_text_empty_options():
text = Text()
text.generate(options = [''])
text.generate(options = {"bool_options": False, "options": "aaa"})
assert isinstance(text.content(),str) and text.content().isascii()


Expand Down
2 changes: 1 addition & 1 deletion tests/voice_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ def test_voice_generated():

def test_voice_noise():
voice = Voice()
assert isinstance(voice.generate(options = ['noise']).to_voice(), Voice)
assert isinstance(voice.generate(options = {"bool_options":True, "options": [False, True]}).to_voice(), Voice)
Loading