mirror of
https://github.com/Paillat-dev/viralfactory.git
synced 2026-01-02 09:16:19 +00:00
I have no time to review my commit
This commit is contained in:
@@ -49,16 +49,18 @@ class GoogleAssetsEngine(BaseAssetsEngine):
|
||||
"num": 1,
|
||||
}
|
||||
os.makedirs("temp", exist_ok=True)
|
||||
self.google.search(
|
||||
search_params=_search_params,
|
||||
path_to_dir="./temp/",
|
||||
custom_image_name="temp",
|
||||
)
|
||||
# we find the file called temp. extension
|
||||
filename = [f for f in os.listdir("./temp/") if f.startswith("temp.")][0]
|
||||
img = mp.ImageClip(f"./temp/{filename}")
|
||||
# delete the temp folder
|
||||
shutil.rmtree("temp")
|
||||
try:
|
||||
self.google.search(
|
||||
search_params=_search_params,
|
||||
path_to_dir="./temp/",
|
||||
custom_image_name="temp",
|
||||
)
|
||||
# we find the file called temp. extension
|
||||
filename = [f for f in os.listdir("./temp/") if f.startswith("temp.")][0]
|
||||
img = mp.ImageClip(f"./temp/{filename}")
|
||||
# delete the temp folder
|
||||
finally:
|
||||
shutil.rmtree("temp")
|
||||
|
||||
img: mp.ImageClip = img.set_duration(end - start)
|
||||
img: mp.ImageClip = img.set_start(start)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from ..BaseEngine import BaseEngine
|
||||
|
||||
|
||||
class BaseAudioBackgroundEngine(BaseEngine):
|
||||
@abstractmethod
|
||||
def get_background(self) -> None:
|
||||
...
|
||||
@@ -0,0 +1,88 @@
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import gradio as gr
|
||||
import moviepy.editor as mp
|
||||
from moviepy.audio.fx.audio_fadein import audio_fadein
|
||||
from moviepy.audio.fx.audio_fadeout import audio_fadeout
|
||||
|
||||
from . import BaseAudioBackgroundEngine
|
||||
|
||||
|
||||
class MusicAudioBackgroundEngine(BaseAudioBackgroundEngine):
|
||||
name = "Music Audio Background Engine"
|
||||
description = "A basic background engine to set the background audio to a music track."
|
||||
num_options = 1
|
||||
|
||||
def __init__(self, options: list[str]):
|
||||
assets = self.get_assets(type="bcg_music")
|
||||
self.background_audio = [asset for asset in assets if asset.data["name"] == options[0]][0]
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_options(cls) -> list:
|
||||
assets = cls.get_assets(type="bcg_music")
|
||||
choices = (
|
||||
[asset.data["name"] for asset in assets]
|
||||
if len(assets) > 0
|
||||
else ["No audios available"]
|
||||
)
|
||||
|
||||
return [
|
||||
gr.Dropdown(
|
||||
choices=choices,
|
||||
label="Background Music",
|
||||
value=choices[0] if len(assets) > 0 else "No audios available",
|
||||
type="value",
|
||||
)
|
||||
]
|
||||
|
||||
def get_background(self):
|
||||
background = mp.AudioFileClip(f"{self.background_audio.path}")
|
||||
self.ctx.credits += f"\n{self.background_audio.data['credits']}"
|
||||
# we add fade in and fade out to the audio
|
||||
background: mp.AudioFileClip = background.fx(audio_fadein, 1).fx(audio_fadeout, 1)
|
||||
# loop the audio to match the duration of the video
|
||||
audio_clips = []
|
||||
while sum([clip.duration for clip in audio_clips]) < self.ctx.duration:
|
||||
audio_clips.append(background)
|
||||
# now we cut the audio to match the duration of the video exactly
|
||||
audio: mp.AudioFileClip = mp.concatenate_audioclips(audio_clips)
|
||||
audio: mp.AudioFileClip = audio.subclip(0, self.ctx.duration)
|
||||
# finally we add a new fade OUT only to the audio
|
||||
audio: mp.AudioFileClip = audio.fx(audio_fadeout, 1)
|
||||
# change volume to 0.5
|
||||
audio: mp.AudioFileClip = audio.volumex(0.5)
|
||||
self.ctx.audio.append(audio)
|
||||
|
||||
@classmethod
|
||||
def get_settings(cls):
|
||||
def add_file(fp: str, name: str, credits: str):
|
||||
if name == "":
|
||||
raise ValueError("Name cannot be empty.")
|
||||
new_fp = f"local/assets/audios/{time.time()}{os.path.splitext(fp)[1]}"
|
||||
shutil.move(fp, new_fp)
|
||||
cls.add_asset(
|
||||
path=new_fp,
|
||||
metadata={"name": name, "credits": credits},
|
||||
type="bcg_music",
|
||||
)
|
||||
gr.Info("Video added successfully.")
|
||||
|
||||
with gr.Column() as add_asset_inputs:
|
||||
add_asset_name = gr.Textbox(label="Name of the audio", value="")
|
||||
add_asset_credits = gr.Textbox(label="Credits", value="")
|
||||
add_asset_input = gr.File(
|
||||
file_count="single",
|
||||
file_types=["audio"],
|
||||
type="filepath",
|
||||
)
|
||||
with gr.Column() as add_asset_button:
|
||||
add_asset_button = gr.Button(value="Add Audio")
|
||||
add_asset_button.click(
|
||||
add_file,
|
||||
inputs=[add_asset_input, add_asset_name, add_asset_credits],
|
||||
outputs=[],
|
||||
)
|
||||
2
src/engines/AudioBackgroundEngine/__init__.py
Normal file
2
src/engines/AudioBackgroundEngine/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .BaseAudioBackgroundEngine import BaseAudioBackgroundEngine
|
||||
from .MusicAudioBackgroundEngine import MusicAudioBackgroundEngine
|
||||
@@ -1,6 +1,6 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from ..BaseEngine import BaseEngine
|
||||
from src.engines.BaseEngine import BaseEngine
|
||||
|
||||
|
||||
class BaseBackgroundEngine(BaseEngine):
|
||||
|
||||
@@ -7,7 +7,6 @@ from ..chore import GenerationContext
|
||||
from ..models import SessionLocal, File, Setting
|
||||
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
class BaseEngine(ABC):
|
||||
num_options: int
|
||||
name: str
|
||||
@@ -15,7 +14,6 @@ class BaseEngine(ABC):
|
||||
|
||||
def __init__(self):
|
||||
self.ctx: GenerationContext # This is for type hinting only
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import gradio as gr
|
||||
import os
|
||||
import shutil
|
||||
from moviepy.editor import TextClip
|
||||
|
||||
from . import BaseCaptioningEngine
|
||||
@@ -80,6 +82,13 @@ class SimpleCaptioningEngine(BaseCaptioningEngine):
|
||||
|
||||
self.ctx.index_7.extend(clips)
|
||||
|
||||
@classmethod
|
||||
def get_settings(cls):
|
||||
gr.Markdown(
|
||||
"To add a custom font, simply install the font on your system, restart the server, and input the exact "
|
||||
"file name (without the path) in the dropdown."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_options(cls) -> list:
|
||||
with gr.Column() as font_options:
|
||||
@@ -87,7 +96,8 @@ class SimpleCaptioningEngine(BaseCaptioningEngine):
|
||||
font = gr.Dropdown(
|
||||
label="Font",
|
||||
choices=TextClip.list("font"),
|
||||
value="Comic-Sans-MS",
|
||||
value="Comic-Sans-MS-Bold",
|
||||
allow_custom_value=True, # Allow custom font
|
||||
)
|
||||
font_size = gr.Number(
|
||||
label="Font Size",
|
||||
|
||||
@@ -2,13 +2,28 @@ from . import BaseEngine
|
||||
|
||||
|
||||
class NoneEngine(BaseEngine):
|
||||
num_options = 0
|
||||
name = "None"
|
||||
description = "No engine selected"
|
||||
"""
|
||||
This class represents a NoneEngine which is a subclass of BaseEngine.
|
||||
It is used when no engine is selected. It does not have any options.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
num_options = 0 # The number of options available for this engine.
|
||||
name = "None" # The name of the engine.
|
||||
description = "No engine selected" # A brief description of the engine.
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Constructor method for the NoneEngine class. It calls the constructor of the BaseEngine class.
|
||||
"""
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_options(cls):
|
||||
return []
|
||||
"""
|
||||
This class method returns the options available for the NoneEngine.
|
||||
Since NoneEngine does not have any options, it returns an empty list.
|
||||
|
||||
Returns:
|
||||
list: An empty list as there are no options for NoneEngine.
|
||||
"""
|
||||
return []
|
||||
37
src/engines/ScriptEngine/ScientificFactsScriptEngine.py
Normal file
37
src/engines/ScriptEngine/ScientificFactsScriptEngine.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import os
|
||||
|
||||
import gradio as gr
|
||||
|
||||
from .BaseScriptEngine import BaseScriptEngine
|
||||
from ...utils.prompting import get_prompt
|
||||
|
||||
|
||||
class ScientificFactsScriptEngine(BaseScriptEngine):
|
||||
name = "Scientific facts Thoughts"
|
||||
description = "Generate a scientific facts script."
|
||||
num_options = 1
|
||||
|
||||
def __init__(self, options: list[list | tuple | str | int | float | bool | None]):
|
||||
self.n_sentences = options[0]
|
||||
super().__init__()
|
||||
|
||||
def generate(self):
|
||||
sys_prompt, chat_prompt = get_prompt(
|
||||
"scientific_facts",
|
||||
location=os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), "prompts"
|
||||
),
|
||||
)
|
||||
sys_prompt = sys_prompt.format(n_sentences=self.n_sentences)
|
||||
chat_prompt = chat_prompt.format(n_sentences=self.n_sentences)
|
||||
self.ctx.script = self.ctx.powerfulllmengine.generate(
|
||||
system_prompt=sys_prompt,
|
||||
chat_prompt=chat_prompt,
|
||||
max_tokens=20 * self.n_sentences,
|
||||
temperature=1.3,
|
||||
json_mode=False,
|
||||
).strip()
|
||||
|
||||
@classmethod
|
||||
def get_options(cls) -> list:
|
||||
return [gr.Number(label="Number of sentences", value=5, minimum=1)]
|
||||
19
src/engines/ScriptEngine/prompts/scientific_facts.yaml
Normal file
19
src/engines/ScriptEngine/prompts/scientific_facts.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
system: |-
|
||||
You are an expert content writer of a YouTube shorts channel. You specialize in scientific facts shorts.
|
||||
Your shorts are {n_sentences} sentences long. This is VERY IMPORTANT, MAKE SURE TO RESPECT THIS LENGTH.
|
||||
They are extremely captivating, and original.
|
||||
You need to follow the following guidelines:
|
||||
- **Hook the Viewer:** Start with a compelling question, fact, or scenario to grab attention immediately. Your fact can also be a bit wierd or shocking (not really shocking, but you get the point), so that the viewer wants to know the actual truth.
|
||||
Specifically, you can start with something that isn't completely correct, then when you continue the actual explanation unfolds, in order to make the first few words more attractive.
|
||||
- **Keep it Short and Sweet:** Deliver your content concisely and rapidly to match the platform's fast-paced nature.
|
||||
- **Tap into Relatability or Curiosity:** Make your content relatable or introduce surprising elements to spark curiosity.
|
||||
- **Maintain a Conversational Tone:** Use conversational language to make your content more accessible and engaging.
|
||||
- **Use Visual Imagery:** Describe concepts in a way that invokes visual imagery, enhancing engagement.
|
||||
- **Include a Call to Action:** End with a direct call to action to encourage viewer interaction if applicable.
|
||||
You are now tasked to produce the greatest short script for the user.
|
||||
Start with a compelling information, fact, or scenario to grab attention IMMEDIATELY.
|
||||
Keep it short, EXTREMELY interesting and original.
|
||||
If it is appropriate, at the end, ask a question to the user, and end point blank.
|
||||
YOU never respond with anything else that the video script, not even a hello.
|
||||
chat: |
|
||||
Please give me a script. Make sure to keep it {n_sentences} sentences long, including any questions or calls to action.
|
||||
@@ -49,7 +49,7 @@ class BaseTTSEngine(BaseEngine):
|
||||
"""
|
||||
device = "cuda" if is_available() else "cpu"
|
||||
audio = wt.load_audio(path)
|
||||
model = wt.load_model("small", device=device)
|
||||
model = wt.load_model("large-v3", device=device)
|
||||
|
||||
result = wt.transcribe(model=model, audio=audio)
|
||||
results = [word for chunk in result["segments"] for word in chunk["words"]]
|
||||
|
||||
@@ -36,11 +36,11 @@ class TikTokUploadEngine(BaseUploadEngine):
|
||||
description = description.replace(word, "")
|
||||
|
||||
title = title.strip()
|
||||
description = description.strip().replace("\n", " ") # Newlines are not supported by this uploader
|
||||
description = description.strip()
|
||||
hashtags_str = " ".join(hashtags) + " " if hashtags else ""
|
||||
failed = upload_video(
|
||||
filename=self.ctx.get_file_path("final.mp4"),
|
||||
description=f"{title} {description} {hashtags_str}",
|
||||
description=f"{title}\n{description} {hashtags_str}",
|
||||
cookies_str=cookies,
|
||||
browser="chrome",
|
||||
comment=True, stitch=False, duet=False
|
||||
|
||||
@@ -7,6 +7,7 @@ from . import ScriptEngine
|
||||
from . import SettingsEngine
|
||||
from . import TTSEngine
|
||||
from . import UploadEngine
|
||||
from . import AudioBackgroundEngine
|
||||
from .BaseEngine import BaseEngine
|
||||
from .NoneEngine import NoneEngine
|
||||
|
||||
@@ -49,7 +50,11 @@ ENGINES: dict[str, dict[str, bool | list[BaseEngine]]] = {
|
||||
"multiple": True,
|
||||
},
|
||||
"BackgroundEngine": {
|
||||
"classes": [BackgroundEngine.VideoBackgroundEngine, NoneEngine],
|
||||
"classes": [NoneEngine, BackgroundEngine.VideoBackgroundEngine],
|
||||
"multiple": False,
|
||||
},
|
||||
"AudioBackgroundEngine": {
|
||||
"classes": [NoneEngine, AudioBackgroundEngine.MusicAudioBackgroundEngine],
|
||||
"multiple": False,
|
||||
},
|
||||
"MetadataEngine": {
|
||||
|
||||
Reference in New Issue
Block a user