Last active
September 9, 2023 13:00
-
-
Save jeffehobbs/23117c0cc1e167c9da6cd1ef315f65f2 to your computer and use it in GitHub Desktop.
ariseCthulhuBot - using ML to summon The Old Ones
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ariseCthulhuBot.py | jeffehobbs@gmail.com | |
# taking the Great Tweets and sending them through the | |
# Lovecraftian-chaotic wheat thresher of the "bark" TTS library | |
# in order to summon The Old Ones | |
# | |
# to-do: | |
# | |
# 1. [X] get a CLASSIC tweet | |
# 2. [X] make a music intro | |
# 3. [X] make a text tweet | |
# 4. [X] laugh track/sfx track | |
# 5. [X] make a music outro | |
# 6. [X] concatinate the audio files | |
# 7. [X] make a ffpeg waveform video | |
# 7a.[X] do it without destroying the host machine | |
# 8. [X] post it on twitter | |
from bark import SAMPLE_RATE, generate_audio, preload_models | |
from scipy.io.wavfile import write as write_wav | |
from pydub import AudioSegment | |
import os, json, random, glob, subprocess, time, configparser, tweepy | |
# globals | |
SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) | |
INPUT_FILE = SCRIPT_PATH + '/input/dril_tweets.txt' | |
FORBIDDEN = ['@','http','bitch'] | |
CREATE_NEW_POST = True | |
# not really sure this does anything but hey | |
os.environ["SUNO_OFFLOAD_CPU"] = "True" | |
os.environ["SUNO_USE_SMALL_MODELS"] = "True" | |
# set up API keys from external config secrets.txt file | |
config = configparser.ConfigParser() | |
config.read(SCRIPT_PATH +'/secrets.txt') | |
TWITTER_CONSUMER_KEY = config.get('twitter', 'consumer_key') | |
TWITTER_CONSUMER_SECRET = config.get('twitter', 'consumer_secret') | |
TWITTER_ACCESS_TOKEN = config.get('twitter', 'access_token') | |
TWITTER_ACCESS_TOKEN_SECRET = config.get('twitter', 'access_token_secret') | |
def get_dril_tweet(INPUT_FILE): | |
print("...getting line from file...") | |
lines = open(INPUT_FILE).read().splitlines() | |
random_line = random.choice(lines) | |
for forbade in FORBIDDEN: | |
if forbade in str(random_line): | |
get_dril_tweet(INPUT_FILE) | |
random_line = '] ' + random_line.replace('. ','.\n] ') | |
return(random_line) | |
def make_music(filename): | |
text_prompt = '[music]' | |
audio_array = generate_audio(text_prompt) | |
write_wav(f"{SCRIPT_PATH}/temp/{filename}.wav", SAMPLE_RATE, audio_array) | |
def make_text(text_prompt): | |
mode_type = random.randint(0, 1) | |
if (mode_type == 0): | |
mode = "♪" | |
else: | |
mode = "" | |
audio_array = generate_audio(mode + ' ' + text_prompt + ' ' + mode) | |
write_wav(f"{SCRIPT_PATH}/temp/text.wav", SAMPLE_RATE, audio_array) | |
def make_sfx_track(): | |
mode_type = random.randint(0, 4) | |
if (mode_type == 0): | |
text_prompt = '[laughs]' | |
elif (mode_type == 1): | |
text_prompt = '[laughter]' | |
elif (mode_type == 2): | |
text_prompt = '[sighs]' | |
elif (mode_type == 3): | |
text_prompt = '[gasps]' | |
else: | |
text_prompt = '[clears throat]' | |
audio_array = generate_audio(text_prompt) | |
write_wav(f"{SCRIPT_PATH}/temp/laughs.wav", SAMPLE_RATE, audio_array) | |
def concatinate_audio(): | |
intro = AudioSegment.from_wav(f"{SCRIPT_PATH}/temp/intro.wav") | |
text = AudioSegment.from_wav(f"{SCRIPT_PATH}/temp/text.wav") | |
laughs = AudioSegment.from_wav(f"{SCRIPT_PATH}/temp/laughs.wav") | |
outro = AudioSegment.from_wav(f"{SCRIPT_PATH}/temp/outro.wav") | |
full_presentation = intro + text + laughs + outro | |
full_presentation.export(f"{SCRIPT_PATH}/temp/audio.mp3", format="mp3") | |
def make_waveform_video(filename, text): | |
mode_type = random.randint(0, 1) | |
if (mode_type == 0): | |
mode = "line" | |
else: | |
mode = "cline" | |
colors = "green" | |
ffmpeg_command = "ffmpeg -hide_banner -loglevel warning -y -i " + filename + " -filter_complex '[0:a]showwaves=size=1280x720:mode=" + mode + ":colors=" + colors + ",format=yuv420p[v]' -map '[v]' -map 0:a -c:v libx264 -c:a copy " + filename.replace(".mp3","_waveform.mp4") | |
print(ffmpeg_command) | |
subprocess.call(ffmpeg_command, shell=True) | |
ffmpeg_command = "ffmpeg -hide_banner -loglevel warning -y -i " + filename.replace(".mp3","_waveform.mp4") + " -i " + filename + " -c:v copy -c:a aac " + SCRIPT_PATH + "/temp/video.mp4" | |
print(ffmpeg_command) | |
subprocess.call(ffmpeg_command, shell=True) | |
text = text.replace('"','').replace("'","").replace(":","") | |
ffmpeg_command = "ffmpeg -hide_banner -loglevel warning -y -i " + SCRIPT_PATH + "/temp/video.mp4 -vf \"drawtext=text='" + text + "':fontfile=" + SCRIPT_PATH + "/fonts/PrintChar21.ttf:fontsize=18:fontcolor=green:x=10:y=10\" -codec:a copy " + SCRIPT_PATH + "/output/video.mp4" | |
print(ffmpeg_command) | |
subprocess.call(ffmpeg_command, shell=True) | |
def clean_up(): | |
files = glob.glob(f'{SCRIPT_PATH}/temp/*') | |
for f in files: | |
os.remove(f) | |
# tweet that stuff | |
def send_tweet(status, media_file_path): | |
media_ids = [] | |
client = tweepy.Client(consumer_key=TWITTER_CONSUMER_KEY, | |
consumer_secret=TWITTER_CONSUMER_SECRET, | |
access_token=TWITTER_ACCESS_TOKEN, | |
access_token_secret=TWITTER_ACCESS_TOKEN_SECRET) | |
auth = tweepy.OAuth1UserHandler( | |
TWITTER_CONSUMER_KEY, | |
TWITTER_CONSUMER_SECRET, | |
TWITTER_ACCESS_TOKEN, | |
TWITTER_ACCESS_TOKEN_SECRET, | |
) | |
api = tweepy.API(auth) | |
media_upload_response = api.media_upload(media_file_path) | |
media_ids.append(media_upload_response.media_id) | |
response = client.create_tweet(text=status, user_auth=True, media_ids=media_ids) | |
return | |
def send_mastodon(status, media_file_path): | |
mastodon = Mastodon( | |
access_token = MASTODON_ACCESS_TOKEN, | |
api_base_url = 'https://botsin.space/' | |
) | |
media = mastodon.media_post(media_file_path, description="Very real photo of the incident") | |
mastodon.status_post(status, media_ids=media) | |
return | |
def main(): | |
start = time.time() | |
if (CREATE_NEW_POST): | |
preload_models( | |
text_use_small=True, | |
coarse_use_small=True, | |
fine_use_gpu=True, | |
fine_use_small=True | |
) | |
text = get_dril_tweet(INPUT_FILE) | |
print(text) | |
make_music('intro') | |
make_text(text) | |
make_sfx_track() | |
make_music('outro') | |
concatinate_audio() | |
make_waveform_video(f'{SCRIPT_PATH}/temp/audio.mp3', text) | |
send_tweet('', f'{SCRIPT_PATH}/output/video.mp4') | |
clean_up() | |
end = time.time() | |
execution_time = int(end - start) | |
print('TIME:' + str(round(execution_time / 60)) + ' minutes') | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment