Skip to content

Commit

Permalink
Added the story mode with 2 methods by Electro199 (#1288)
Browse files Browse the repository at this point in the history
Thank you @electro199!
  • Loading branch information
electro199 authored Dec 19, 2022
1 parent 903dc34 commit e30eaf7
Show file tree
Hide file tree
Showing 27 changed files with 831 additions and 255 deletions.
13 changes: 10 additions & 3 deletions TTS/TikTok.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,25 @@ def run(self, text, filepath, random_voice: bool = False):
voice = (
self.randomvoice()
if random_voice
else (settings.config["settings"]["tts"]["tiktok_voice"] or random.choice(self.voices["human"]))
else (
settings.config["settings"]["tts"]["tiktok_voice"]
or random.choice(self.voices["human"])
)
)
try:
r = requests.post(f"{self.URI_BASE}{voice}&req_text={text}&speaker_map_type=0")
r = requests.post(
f"{self.URI_BASE}{voice}&req_text={text}&speaker_map_type=0"
)
except requests.exceptions.SSLError:
# https://stackoverflow.com/a/47475019/18516611
session = requests.Session()
retry = Retry(connect=3, backoff_factor=0.5)
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)
r = session.post(f"{self.URI_BASE}{voice}&req_text={text}&speaker_map_type=0")
r = session.post(
f"{self.URI_BASE}{voice}&req_text={text}&speaker_map_type=0"
)
# print(r.text)
vstr = [r.json()["data"]["v_str"]][0]
b64d = base64.b64decode(vstr)
Expand Down
12 changes: 9 additions & 3 deletions TTS/aws_polly.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ def run(self, text, filepath, random_voice: bool = False):
voice = self.randomvoice()
else:
if not settings.config["settings"]["tts"]["aws_polly_voice"]:
raise ValueError(f"Please set the TOML variable AWS_VOICE to a valid voice. options are: {voices}")
voice = str(settings.config["settings"]["tts"]["aws_polly_voice"]).capitalize()
raise ValueError(
f"Please set the TOML variable AWS_VOICE to a valid voice. options are: {voices}"
)
voice = str(
settings.config["settings"]["tts"]["aws_polly_voice"]
).capitalize()
try:
# Request speech synthesis
response = polly.synthesize_speech(Text=text, OutputFormat="mp3", VoiceId=voice, Engine="neural")
response = polly.synthesize_speech(
Text=text, OutputFormat="mp3", VoiceId=voice, Engine="neural"
)
except (BotoCoreError, ClientError) as error:
# The service returned an error, exit gracefully
print(error)
Expand Down
114 changes: 62 additions & 52 deletions TTS/engine_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from utils.console import print_step, print_substep
from utils.voice import sanitize_text

DEFAULT_MAX_LENGTH: int = 50 # video length variable
DEFAULT_MAX_LENGTH: int = 50 # video length variable


class TTSEngine:
Expand All @@ -45,6 +45,7 @@ def __init__(
):
self.tts_module = tts_module()
self.reddit_object = reddit_object

self.redditid = re.sub(r"[^\w\s-]", "", reddit_object["thread_id"])
self.path = path + self.redditid + "/mp3"
self.max_length = max_length
Expand All @@ -54,39 +55,52 @@ def __init__(
def run(self) -> Tuple[int, int]:

Path(self.path).mkdir(parents=True, exist_ok=True)

# This file needs to be removed in case this post does not use post text, so that it won't appear in the final video
try:
Path(f"{self.path}/posttext.mp3").unlink()
except OSError:
pass

print_step("Saving Text to MP3 files...")

self.call_tts("title", process_text(self.reddit_object["thread_title"]))
processed_text = process_text(self.reddit_object["thread_post"])
if processed_text != "" and settings.config["settings"]["storymode"] == True:
self.call_tts("posttext", processed_text)

# processed_text = ##self.reddit_object["thread_post"] != ""
idx = None
for idx, comment in track(enumerate(self.reddit_object["comments"]), "Saving..."):
# ! Stop creating mp3 files if the length is greater than max length.
if self.length > self.max_length:
self.length -= self.last_clip_length
idx -= 1
break
if len(comment["comment_body"]) > self.tts_module.max_chars: # Split the comment if it is too long
self.split_post(comment["comment_body"], idx) # Split the comment
else: # If the comment is not too long, just call the tts engine
self.call_tts(f"{idx}", process_text(comment["comment_body"]))

if settings.config["settings"]["storymode"]:
if settings.config["settings"]["storymodemethod"] == 0:
if len(self.reddit_object["thread_post"]) > self.tts_module.max_chars:
self.split_post(self.reddit_object["thread_post"], "postaudio")
else:
self.call_tts(
"postaudio", process_text(self.reddit_object["thread_post"])
)
elif settings.config["settings"]["storymodemethod"] == 1:

for idx, text in track(enumerate(self.reddit_object["thread_post"])):
self.call_tts(f"postaudio-{idx}", process_text(text))

else:

for idx, comment in track(
enumerate(self.reddit_object["comments"]), "Saving..."
):
# ! Stop creating mp3 files if the length is greater than max length.
if self.length > self.max_length and idx > 1:
self.length -= self.last_clip_length
idx -= 1
break
if (
len(comment["comment_body"]) > self.tts_module.max_chars
): # Split the comment if it is too long
self.split_post(comment["comment_body"], idx) # Split the comment
else: # If the comment is not too long, just call the tts engine
self.call_tts(f"{idx}", process_text(comment["comment_body"]))

print_substep("Saved Text to MP3 files successfully.", style="bold green")
return self.length, idx

def split_post(self, text: str, idx: int):
def split_post(self, text: str, idx):
split_files = []
split_text = [
x.group().strip() for x in re.finditer(r" *(((.|\n){0," + str(self.tts_module.max_chars) + "})(\.|.$))", text)
x.group().strip()
for x in re.finditer(
r" *(((.|\n){0," + str(self.tts_module.max_chars) + "})(\.|.$))", text
)
]
self.create_silence_mp3()

Expand All @@ -100,15 +114,19 @@ def split_post(self, text: str, idx: int):
continue
else:
self.call_tts(f"{idx}-{idy}.part", newtext)
with open(f"{self.path}/list.txt", 'w') as f:
with open(f"{self.path}/list.txt", "w") as f:
for idz in range(0, len(split_text)):
f.write("file " + f"'{idx}-{idz}.part.mp3'" + "\n")
split_files.append(str(f"{self.path}/{idx}-{idy}.part.mp3"))
f.write("file " + f"'silence.mp3'" + "\n")

os.system("ffmpeg -f concat -y -hide_banner -loglevel panic -safe 0 " +
"-i " + f"{self.path}/list.txt " +
"-c copy " + f"{self.path}/{idx}.mp3")
os.system(
"ffmpeg -f concat -y -hide_banner -loglevel panic -safe 0 "
+ "-i "
+ f"{self.path}/list.txt "
+ "-c copy "
+ f"{self.path}/{idx}.mp3"
)
try:
for i in range(0, len(split_files)):
os.unlink(split_files[i])
Expand All @@ -118,43 +136,35 @@ def split_post(self, text: str, idx: int):
print("OSError")

def call_tts(self, filename: str, text: str):

self.tts_module.run(text, filepath=f"{self.path}/{filename}.mp3")
# try:
# self.length += MP3(f"{self.path}/{filename}.mp3").info.length
# except (MutagenError, HeaderNotFoundError):
# self.length += sox.file_info.duration(f"{self.path}/{filename}.mp3")
try:
self.tts_module.run(text, filepath=f"{self.path}/{filename}_no_silence.mp3")
self.create_silence_mp3()

with open(f"{self.path}/{filename}.txt", 'w') as f:
f.write("file " + f"'{filename}_no_silence.mp3'" + "\n")
f.write("file " + f"'silence.mp3'" + "\n")
f.close()
os.system("ffmpeg -f concat -y -hide_banner -loglevel panic -safe 0 " +
"-i " + f"{self.path}/{filename}.txt " +
"-c copy " + f"{self.path}/{filename}.mp3")
clip = AudioFileClip(f"{self.path}/{filename}.mp3")
self.length += clip.duration
self.last_clip_length = clip.duration
self.length += clip.duration
clip.close()
try:
name = [f"{filename}_no_silence.mp3", "silence.mp3", f"{filename}.txt"]
for i in range(0, len(name)):
os.unlink(str(rf"{self.path}/" + name[i]))
except FileNotFoundError as e:
print("File not found: " + e.filename)
except OSError:
print("OSError")
except:
self.length = 0

def create_silence_mp3(self):
silence_duration = settings.config["settings"]["tts"]["silence_duration"]
silence = AudioClip(make_frame=lambda t: np.sin(440 * 2 * np.pi * t), duration=silence_duration, fps=44100)
silence = AudioClip(
make_frame=lambda t: np.sin(440 * 2 * np.pi * t),
duration=silence_duration,
fps=44100,
)
silence = volumex(silence, 0)
silence.write_audiofile(f"{self.path}/silence.mp3", fps=44100, verbose=False, logger=None)
silence.write_audiofile(
f"{self.path}/silence.mp3", fps=44100, verbose=False, logger=None
)


def process_text(text: str):
def process_text(text: str , clean : bool = True):
lang = settings.config["reddit"]["thread"]["post_lang"]
new_text = sanitize_text(text)
new_text = sanitize_text(text) if clean else text
if lang:
print_substep("Translating Text...")
translated_text = ts.google(text, to_language=lang)
Expand Down
8 changes: 6 additions & 2 deletions TTS/pyttsx.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ def run(
if voice_id == "" or voice_num == "":
voice_id = 2
voice_num = 3
raise ValueError("set pyttsx values to a valid value, switching to defaults")
raise ValueError(
"set pyttsx values to a valid value, switching to defaults"
)
else:
voice_id = int(voice_id)
voice_num = int(voice_num)
Expand All @@ -32,7 +34,9 @@ def run(
voice_id = self.randomvoice()
engine = pyttsx3.init()
voices = engine.getProperty("voices")
engine.setProperty("voice", voices[voice_id].id) # changing index changes voices but ony 0 and 1 are working here
engine.setProperty(
"voice", voices[voice_id].id
) # changing index changes voices but ony 0 and 1 are working here
engine.save_to_file(text, f"{filepath}")
engine.runAndWait()

Expand Down
8 changes: 6 additions & 2 deletions TTS/streamlabs_polly.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ def run(self, text, filepath, random_voice: bool = False):
voice = self.randomvoice()
else:
if not settings.config["settings"]["tts"]["streamlabs_polly_voice"]:
raise ValueError(f"Please set the config variable STREAMLABS_POLLY_VOICE to a valid voice. options are: {voices}")
voice = str(settings.config["settings"]["tts"]["streamlabs_polly_voice"]).capitalize()
raise ValueError(
f"Please set the config variable STREAMLABS_POLLY_VOICE to a valid voice. options are: {voices}"
)
voice = str(
settings.config["settings"]["tts"]["streamlabs_polly_voice"]
).capitalize()
body = {"voice": voice, "text": text, "service": "polly"}
response = requests.post(self.url, data=body)
if not check_ratelimit(response):
Expand Down
Loading

1 comment on commit e30eaf7

@egergwtw
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how to use this?
i need the story mode

Please sign in to comment.