diff --git a/interfaces/__init__.py b/interfaces/__init__.py deleted file mode 100644 index 804bb64..0000000 --- a/interfaces/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .gradio_ui import GenerateUI \ No newline at end of file diff --git a/interfaces/gradio_ui.py b/interfaces/gradio_ui.py deleted file mode 100644 index 4944618..0000000 --- a/interfaces/gradio_ui.py +++ /dev/null @@ -1,51 +0,0 @@ -import importlib -import json -import os -import gradio as gr -from src import engines - -class GenerateUI: - def __init__(self): - self.engines = self.get_engines() - - def get_engines(self): - engines_d = {} - with open(os.path.join(os.getcwd(), "src", "engines", "engines.json"), "r") as f: - engine_types = json.load(f) - for engine_type, engine_list in engine_types.items(): - engines_d[engine_type] = {} - for engine_name in engine_list: - module = importlib.import_module(f"src.engines.{engine_type}.{engine_name}") - engine_class = getattr(module, engine_name) - engines_d[engine_type][engine_name] = engine_class - return engines_d - - def launch_ui(self): - with gr.Blocks() as main_block: - for engine_type, engines in self.engines.items(): - switch_dropdown = gr.Dropdown(list(engines.keys()), label=engine_type) - engine_blocks = [] - - for engine_name, engine_class in engines.items(): - with gr.Blocks(elem_id=f"{engine_type}_{engine_name}_block", visible=False) as engine_block: - options = engine_class().get_options() - for option in options: - engine_block.add(option) - engine_blocks.append(engine_block) - - def switch_engine(engine_name, engine_blocks=engine_blocks, switch_dropdown=switch_dropdown): - for block in engine_blocks: - block.visible = block.elem_id.startswith(f"{engine_type}_{engine_name}") - - switch_dropdown.change(switch_engine, inputs=[switch_dropdown], outputs=engine_blocks) - - # Initially show the first engine's options - if engines: - first_engine_name = list(engines.keys())[0] - switch_engine(first_engine_name) - - main_block.launch() - -if __name__ == "__main__": - ui_generator = GenerateUI() - ui_generator.launch_ui() diff --git a/main.py b/main.py index af6874a..3c74979 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -from interfaces import GenerateUI +from ui import GenerateUI if __name__ == "__main__": ui_generator = GenerateUI() diff --git a/requirements.txt b/requirements.txt index db21aa4..762185b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -62,4 +62,5 @@ typing_extensions==4.9.0 tzdata==2024.1 urllib3==2.2.0 uvicorn==0.27.1 -websockets==11.0.3 \ No newline at end of file +websockets==11.0.3 +TTS \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py index 8b451d9..7c11d54 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1 +1 @@ -from . import engines \ No newline at end of file +from . import engines diff --git a/src/engines/BaseEngine.py b/src/engines/BaseEngine.py index deda7a2..aade7ab 100644 --- a/src/engines/BaseEngine.py +++ b/src/engines/BaseEngine.py @@ -1,10 +1,16 @@ from abc import ABC, abstractmethod import gradio as gr + class BaseEngine(ABC): - options: list + num_options: int name: str description: str def __init__(self): - pass \ No newline at end of file + pass + + @classmethod + @abstractmethod + def get_options(): + ... diff --git a/src/engines/LLMEngine/BaseLLMEngine.py b/src/engines/LLMEngine/BaseLLMEngine.py new file mode 100644 index 0000000..1250b01 --- /dev/null +++ b/src/engines/LLMEngine/BaseLLMEngine.py @@ -0,0 +1,10 @@ +from abc import ABC, abstractmethod +from ..BaseEngine import BaseEngine + +import openai + +class BaseLLMEngine(BaseEngine): + + @abstractmethod + def generate(self, system_prompt: str, chat_prompt: str, max_tokens: int, temperature: float, top_p: float, frequency_penalty: float, presence_penalty: float) -> str: + pass \ No newline at end of file diff --git a/src/engines/LLMEngine/OpenaiLLMEngine.py b/src/engines/LLMEngine/OpenaiLLMEngine.py new file mode 100644 index 0000000..2447e36 --- /dev/null +++ b/src/engines/LLMEngine/OpenaiLLMEngine.py @@ -0,0 +1,29 @@ +import openai +import gradio as gr + +from abc import ABC, abstractmethod + +from .BaseLLMEngine import BaseLLMEngine + +OPENAI_POSSIBLE_MODELS = [ + "gpt-3.5-turbo-0125", + "gpt-4-turbo-preview", +] + +class OpenaiLLMEngine(BaseLLMEngine): + num_options = 1 + name = "OpenAI" + description = "OpenAI language model engine." + + def generate(self, system_prompt: str, chat_prompt: str, max_tokens: int = 512, temperature: float = 1.0, json_mode: bool= False, top_p: float = 1, frequency_penalty: float = 0, presence_penalty: float = 0) -> str: + ... # TODO: Implement this method + + def get_options(self) -> list: + return [ + gr.Dropdown( + label="Model", + choices=OPENAI_POSSIBLE_MODELS, + max_choices=1, + value=OPENAI_POSSIBLE_MODELS[0] + ) + ] \ No newline at end of file diff --git a/src/engines/LLMEngine/__init__.py b/src/engines/LLMEngine/__init__.py new file mode 100644 index 0000000..f79e65d --- /dev/null +++ b/src/engines/LLMEngine/__init__.py @@ -0,0 +1 @@ +from .BaseLLMEngine import BaseLLMEngine \ No newline at end of file diff --git a/src/engines/ScriptEngine/BaseScriptEngine.py b/src/engines/ScriptEngine/BaseScriptEngine.py new file mode 100644 index 0000000..a60f305 --- /dev/null +++ b/src/engines/ScriptEngine/BaseScriptEngine.py @@ -0,0 +1,10 @@ +from abc import ABC, abstractmethod +from ..BaseEngine import BaseEngine + + +class BaseScriptEngine(BaseEngine): + pass + + @abstractmethod + def generate(self) -> str: + pass diff --git a/src/engines/ScriptEngine/ShowerThoughtsScriptEngine.py b/src/engines/ScriptEngine/ShowerThoughtsScriptEngine.py new file mode 100644 index 0000000..92d81b0 --- /dev/null +++ b/src/engines/ScriptEngine/ShowerThoughtsScriptEngine.py @@ -0,0 +1,18 @@ +from .BaseScriptEngine import BaseScriptEngine +import gradio as gr + + +class ShowerThoughtsScriptEngine(BaseScriptEngine): + name = "Shower Thoughts" + description = "Generate a Shower Thoughts script" + num_options = 0 + + def __init__(self, options: list[list | tuple | str | int | float | bool | None]): + super().__init__() + + def generate(self, text: str, path: str) -> str: + pass + + @classmethod + def get_options(cls) -> list: + return [] diff --git a/src/engines/ScriptEngine/__init__.py b/src/engines/ScriptEngine/__init__.py new file mode 100644 index 0000000..c2e8e3f --- /dev/null +++ b/src/engines/ScriptEngine/__init__.py @@ -0,0 +1,2 @@ +from .BaseScriptEngine import BaseScriptEngine +from .ShowerThoughtsScriptEngine import ShowerThoughtsScriptEngine diff --git a/src/engines/TTSEngine/BaseTTSEngine.py b/src/engines/TTSEngine/BaseTTSEngine.py index 0736ea0..51ad549 100644 --- a/src/engines/TTSEngine/BaseTTSEngine.py +++ b/src/engines/TTSEngine/BaseTTSEngine.py @@ -7,4 +7,4 @@ class BaseTTSEngine(BaseEngine): @abstractmethod def synthesize(self, text: str, path: str) -> str: - pass \ No newline at end of file + pass diff --git a/src/engines/TTSEngine/CoquiTTSEngine.py b/src/engines/TTSEngine/CoquiTTSEngine.py index 02afe46..0661594 100644 --- a/src/engines/TTSEngine/CoquiTTSEngine.py +++ b/src/engines/TTSEngine/CoquiTTSEngine.py @@ -1,7 +1,9 @@ import gradio as gr -import TTS + +# import TTS import os -import torch + +# import torch from .BaseTTSEngine import BaseTTSEngine @@ -88,20 +90,7 @@ class CoquiTTSEngine(BaseTTSEngine): "ko", # Korean "hi", # Hindi ] - options = [ - { - "type": "dropdown", - "label": "Voice", - "choices": voices, - "max": 1, - }, - { - "type": "dropdown", - "label": "Language", - "choices": languages, - "max": 1, - }, - ] + num_options = 2 def __init__(self, options: list): super().__init__() @@ -110,10 +99,28 @@ class CoquiTTSEngine(BaseTTSEngine): self.language = options[1][0] os.environ["COQUI_TOS_AGREED"] = "1" - self.tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2") - device = "cuda" if torch.cuda.is_available() else "cpu" - self.tts.to(device) + + # self.tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2") + # device = "cuda" if torch.cuda.is_available() else "cpu" + # self.tts.to(device) def synthesize(self, text: str, path: str) -> str: - self.tts.tts_to_file(text=text, file_path=path, lang=self.language, speaker=self.voice) - return path \ No newline at end of file + # self.tts.tts_to_file(text=text, file_path=path, lang=self.language, speaker=self.voice) + return path + + @classmethod + def get_options(cls) -> list: + return [ + gr.Dropdown( + label="Voice", + choices=cls.voices, + max_choices=1, + value=cls.voices[0], + ), + gr.Dropdown( + label="Language", + choices=cls.languages, + max_choices=1, + value=cls.languages[0], + ), + ] diff --git a/src/engines/TTSEngine/ElevenLabsTTSEngine.py b/src/engines/TTSEngine/ElevenLabsTTSEngine.py index b87b969..3e34850 100644 --- a/src/engines/TTSEngine/ElevenLabsTTSEngine.py +++ b/src/engines/TTSEngine/ElevenLabsTTSEngine.py @@ -1,38 +1,19 @@ from .BaseTTSEngine import BaseTTSEngine import gradio as gr + class ElevenLabsTTSEngine(BaseTTSEngine): - options = [ - { - "type": "dropdown", - "label": "Voice", - "choices": [ - "Zofija Kendrick", - "Narelle Moon", - "Barbora MacLean", - "Alexandra Hisakawa", - "Alma María", - "Rosemary Okafor", - "Ige Behringer", - "Filip Traverse", - "Damjan Chapman", - "Wulf Carlevaro", - "Aaron Dreschner", - "Kumar Dahl", - "Eugenio Mataracı", - "Ferran Simen", - "Xavier Hayasaka", - "Luis Moray", - "Marcos Rudaski", - ], - } - ] name = "ElevenLabs" description = "ElevenLabs TTS engine." + num_options = 0 def __init__(self, options: list[list | tuple | str | int | float | bool | None]): - self.voice = options[0][0] + # self.voice = options[0][0] super().__init__() def synthesize(self, text: str, path: str) -> str: - pass \ No newline at end of file + pass + + @classmethod + def get_options(cls) -> list: + return [] diff --git a/src/engines/TTSEngine/__init__.py b/src/engines/TTSEngine/__init__.py index a2fc797..5ee9a3d 100644 --- a/src/engines/TTSEngine/__init__.py +++ b/src/engines/TTSEngine/__init__.py @@ -1,3 +1,3 @@ from .BaseTTSEngine import BaseTTSEngine from .CoquiTTSEngine import CoquiTTSEngine -from .ElevenLabsTTSEngine import ElevenLabsTTSEngine \ No newline at end of file +from .ElevenLabsTTSEngine import ElevenLabsTTSEngine diff --git a/src/engines/__init__.py b/src/engines/__init__.py index 62eb7ea..8562586 100644 --- a/src/engines/__init__.py +++ b/src/engines/__init__.py @@ -1,2 +1,8 @@ from . import TTSEngine -from .BaseEngine import BaseEngine \ No newline at end of file +from .BaseEngine import BaseEngine +from . import ScriptEngine + +ENGINES = { + "TTSEngine": [TTSEngine.CoquiTTSEngine, TTSEngine.ElevenLabsTTSEngine], + "ScriptEngine": [ScriptEngine.ShowerThoughtsScriptEngine], +} diff --git a/src/engines/script/AbstractScriptEngine.py b/src/engines/script/AbstractScriptEngine.py deleted file mode 100644 index e5f1806..0000000 --- a/src/engines/script/AbstractScriptEngine.py +++ /dev/null @@ -1,4 +0,0 @@ -from src.engines.BaseEngine import AbstractEngine - -class AbstractScriptEngine(AbstractEngine): - pass diff --git a/src/engines/script/ComicalScriptEngine.py b/src/engines/script/ComicalScriptEngine.py deleted file mode 100644 index eb7d667..0000000 --- a/src/engines/script/ComicalScriptEngine.py +++ /dev/null @@ -1,6 +0,0 @@ -from AbstractScriptEngine import AbstractScriptEngine - -class ComicalScriptEngine(AbstractScriptEngine): - def __init__(self): - super().__init__() - self.options = {"comicality": ["Low", "Medium", "High"]} diff --git a/src/engines/script/DrammaticScriptEngine.py b/src/engines/script/DrammaticScriptEngine.py deleted file mode 100644 index 024b52a..0000000 --- a/src/engines/script/DrammaticScriptEngine.py +++ /dev/null @@ -1,6 +0,0 @@ -from AbstractScriptEngine import AbstractScriptEngine - -class DramaticScriptEngine(AbstractScriptEngine): - def __init__(self): - super().__init__() - self.options = {"tone": ["Serious", "Light-hearted"]} diff --git a/ui/__init__.py b/ui/__init__.py new file mode 100644 index 0000000..1fa9572 --- /dev/null +++ b/ui/__init__.py @@ -0,0 +1 @@ +from .gradio_ui import GenerateUI diff --git a/ui/gradio_ui.py b/ui/gradio_ui.py new file mode 100644 index 0000000..cc4f5b6 --- /dev/null +++ b/ui/gradio_ui.py @@ -0,0 +1,95 @@ +import os +import gradio as gr +from src.engines import ENGINES + + +class GenerateUI: + def __init__(self): + self.css = """.generate_button { + font-size: 5rem !important + } + """ + + def get_switcher_func(self, engine_names: list[str]) -> list[gr.update]: + def switch(selected: str): + returnable = [] + for i, name in enumerate(engine_names): + returnable.append(gr.update(visible=name == selected)) + + return returnable + + return switch + + def launch_ui(self): + ui = gr.TabbedInterface( + *self.get_interfaces(), + "Viral Automator", + "NoCrypt/miku", + css=self.css + ) + ui.launch() + + def get_interfaces(self) -> tuple[list[gr.Blocks], list[str]]: + """ + Returns a tuple containing a list of gr.Blocks interfaces and a list of interface names. + + Returns: + tuple[list[gr.Blocks], list[str]]: A tuple containing a list of gr.Blocks interfaces and a list of interface names. + """ + return ([self.get_generate_interface()], ["Generate"]) + + def get_generate_interface(self) -> gr.Blocks: + with gr.Blocks() as interface: + with gr.Row() as row: + inputs = [] + with gr.Blocks() as col1: + for engine_type, engines in ENGINES.items(): + with gr.Tab(engine_type) as engine_tab: + engine_names = [engine.name for engine in engines] + engine_dropdown = gr.Dropdown( + choices=engine_names, value=engine_names[0] + ) + inputs.append(engine_dropdown) + engine_rows = [] + for i, engine in enumerate(engines): + with gr.Row(visible=(i == 0)) as engine_row: + engine_rows.append(engine_row) + options = engine.get_options() + inputs.extend(options) + switcher = self.get_switcher_func(engine_names) + engine_dropdown.change( + switcher, inputs=engine_dropdown, outputs=engine_rows + ) + + with gr.Blocks() as col2: + button = gr.Button("🚀", size="lg", variant="primary", elem_classes="generate_button") + button.click(self.repack_options, inputs=inputs) + return interface + + def repack_options(self, *args): + """ + Repacks the options provided as arguments into a dictionary based on the selected engine. + + Args: + *args: Variable number of arguments representing the options for each engine. + + Returns: + dict: A dictionary containing the repacked options, where the keys are the engine types and the values are the corresponding engine options. + """ + options = {} + args = list(args) + for engine_type, engines in ENGINES.items(): + engine_name = args.pop(0) + for engine in engines: + if engine.name == engine_name: + options[engine_type] = engine(options=args[: engine.num_options]) + args = args[engine.num_options :] + else: + # we don't care about this, it's not the selected engine, we throw it away + args = args[engine.num_options :] + print(options) + + +if __name__ == "__main__": + ui_generator = GenerateUI() + ui_generator.launch_ui()