diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..c7d9f3332a950355d5a77d85000f05e6f45435ea --- /dev/null +++ b/.gitattributes @@ -0,0 +1,34 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..04a65446f300f8648d950055761c4c2493cc75a8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.10 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install -r requirements.txt + +RUN mkdir /.cache && chmod -R 777 /.cache +RUN mkdir .chroma && chmod -R 777 .chroma + +COPY . . + +RUN chmod -R 777 /app + +EXPOSE 7860 + +CMD ["python", "server.py", "--cpu", "--share", "--secure", "--enable-modules=summarize,classify,silero-tts,edge-tts,chromadb", "--classification-model=joeddav/distilbert-base-uncased-go-emotions-student", "--summarization-model=slauw87/bart_summarisation"] diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..54bdf565cf8696ff5b40892c78b7f853cde7d0ac --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +--- +title: zeeka5456 +emoji: 🐠 +colorFrom: pink +colorTo: yellow +sdk: docker +pinned: false +license: mit +duplicated_from: doctord98/zeeka5456 +--- +Doctord98 is the boss \ No newline at end of file diff --git a/constants.py b/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..66c62a64e5d02d65c70c89b39affa6b689b5ac9b --- /dev/null +++ b/constants.py @@ -0,0 +1,49 @@ +# Constants +# Also try: 'Qiliang/bart-large-cnn-samsum-ElectrifAi_v10' +DEFAULT_SUMMARIZATION_MODEL = "Qiliang/bart-large-cnn-samsum-ChatGPT_v3" +# Also try: 'joeddav/distilbert-base-uncased-go-emotions-student' +DEFAULT_CLASSIFICATION_MODEL = "nateraw/bert-base-uncased-emotion" +# Also try: 'Salesforce/blip-image-captioning-base' +DEFAULT_CAPTIONING_MODEL = "Salesforce/blip-image-captioning-large" +DEFAULT_SD_MODEL = "ckpt/anything-v4.5-vae-swapped" +DEFAULT_EMBEDDING_MODEL = "sentence-transformers/all-mpnet-base-v2" +DEFAULT_REMOTE_SD_HOST = "127.0.0.1" +DEFAULT_REMOTE_SD_PORT = 7860 +DEFAULT_CHROMA_PORT = 8000 +SILERO_SAMPLES_PATH = "tts_samples" +SILERO_SAMPLE_TEXT = "The quick brown fox jumps over the lazy dog" +# ALL_MODULES = ['caption', 'summarize', 'classify', 'keywords', 'prompt', 'sd'] +DEFAULT_SUMMARIZE_PARAMS = { + "temperature": 1.0, + "repetition_penalty": 1.0, + "max_length": 500, + "min_length": 200, + "length_penalty": 1.5, + "bad_words": [ + "\n", + '"', + "*", + "[", + "]", + "{", + "}", + ":", + "(", + ")", + "<", + ">", + "Â", + "The text ends", + "The story ends", + "The text is", + "The story is", + ], +} + +PROMPT_PREFIX = "best quality, absurdres, " +NEGATIVE_PROMPT = """lowres, bad anatomy, error body, error hair, error arm, +error hands, bad hands, error fingers, bad fingers, missing fingers +error legs, bad legs, multiple legs, missing legs, error lighting, +error shadow, error reflection, text, error, extra digit, fewer digits, +cropped, worst quality, low quality, normal quality, jpeg artifacts, +signature, watermark, username, blurry""" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..40e6f8ca42fc80f9613490a78f0a176302f4c52f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,20 @@ +flask +flask-cloudflared +flask-cors +flask-compress +markdown +Pillow +colorama +webuiapi +--extra-index-url https://download.pytorch.org/whl/cu117 +torch==2.0.0+cu117 +torchvision==0.15.1 +torchaudio==2.0.1+cu117 +accelerate +transformers==4.28.1 +diffusers==0.16.1 +silero-api-server +chromadb +sentence_transformers +edge-tts +Werkzeug \ No newline at end of file diff --git a/server.py b/server.py new file mode 100644 index 0000000000000000000000000000000000000000..c24e7ab2059ea9554094663fccf8d9145439fbf0 --- /dev/null +++ b/server.py @@ -0,0 +1,844 @@ +from functools import wraps +from flask import ( + Flask, + jsonify, + request, + Response, + render_template_string, + abort, + send_from_directory, + send_file, +) +from flask_cors import CORS +from flask_compress import Compress +import markdown +import argparse +from transformers import AutoTokenizer, AutoProcessor, pipeline +from transformers import AutoModelForCausalLM, AutoModelForSeq2SeqLM +from transformers import BlipForConditionalGeneration +import unicodedata +import torch +import time +import os +import gc +import secrets +from PIL import Image +import base64 +from io import BytesIO +from random import randint +import webuiapi +import hashlib +from constants import * +from colorama import Fore, Style, init as colorama_init + +colorama_init() + + +class SplitArgs(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + setattr( + namespace, self.dest, values.replace('"', "").replace("'", "").split(",") + ) + + +# Script arguments +parser = argparse.ArgumentParser( + prog="SillyTavern Extras", description="Web API for transformers models" +) +parser.add_argument( + "--port", type=int, help="Specify the port on which the application is hosted" +) +parser.add_argument( + "--listen", action="store_true", help="Host the app on the local network" +) +parser.add_argument( + "--share", action="store_true", help="Share the app on CloudFlare tunnel" +) +parser.add_argument("--cpu", action="store_true", help="Run the models on the CPU") +parser.add_argument("--summarization-model", help="Load a custom summarization model") +parser.add_argument( + "--classification-model", help="Load a custom text classification model" +) +parser.add_argument("--captioning-model", help="Load a custom captioning model") +parser.add_argument("--embedding-model", help="Load a custom text embedding model") +parser.add_argument("--chroma-host", help="Host IP for a remote ChromaDB instance") +parser.add_argument("--chroma-port", help="HTTP port for a remote ChromaDB instance (defaults to 8000)") +parser.add_argument("--chroma-folder", help="Path for chromadb persistence folder", default='.chroma_db') +parser.add_argument( + "--secure", action="store_true", help="Enforces the use of an API key" +) + +sd_group = parser.add_mutually_exclusive_group() + +local_sd = sd_group.add_argument_group("sd-local") +local_sd.add_argument("--sd-model", help="Load a custom SD image generation model") +local_sd.add_argument("--sd-cpu", help="Force the SD pipeline to run on the CPU") + +remote_sd = sd_group.add_argument_group("sd-remote") +remote_sd.add_argument( + "--sd-remote", action="store_true", help="Use a remote backend for SD" +) +remote_sd.add_argument( + "--sd-remote-host", type=str, help="Specify the host of the remote SD backend" +) +remote_sd.add_argument( + "--sd-remote-port", type=int, help="Specify the port of the remote SD backend" +) +remote_sd.add_argument( + "--sd-remote-ssl", action="store_true", help="Use SSL for the remote SD backend" +) +remote_sd.add_argument( + "--sd-remote-auth", + type=str, + help="Specify the username:password for the remote SD backend (if required)", +) + +parser.add_argument( + "--enable-modules", + action=SplitArgs, + default=[], + help="Override a list of enabled modules", +) + +args = parser.parse_args() + +port = 7860 +host = "0.0.0.0" +summarization_model = ( + args.summarization_model + if args.summarization_model + else DEFAULT_SUMMARIZATION_MODEL +) +classification_model = ( + args.classification_model + if args.classification_model + else DEFAULT_CLASSIFICATION_MODEL +) +captioning_model = ( + args.captioning_model if args.captioning_model else DEFAULT_CAPTIONING_MODEL +) +embedding_model = ( + args.embedding_model if args.embedding_model else DEFAULT_EMBEDDING_MODEL +) + +sd_use_remote = False if args.sd_model else True +sd_model = args.sd_model if args.sd_model else DEFAULT_SD_MODEL +sd_remote_host = args.sd_remote_host if args.sd_remote_host else DEFAULT_REMOTE_SD_HOST +sd_remote_port = args.sd_remote_port if args.sd_remote_port else DEFAULT_REMOTE_SD_PORT +sd_remote_ssl = args.sd_remote_ssl +sd_remote_auth = args.sd_remote_auth + +modules = ( + args.enable_modules if args.enable_modules and len(args.enable_modules) > 0 else [] +) + +if len(modules) == 0: + print( + f"{Fore.RED}{Style.BRIGHT}You did not select any modules to run! Choose them by adding an --enable-modules option" + ) + print(f"Example: --enable-modules=caption,summarize{Style.RESET_ALL}") + +# Models init +device_string = "cuda:0" if torch.cuda.is_available() and not args.cpu else "cpu" +device = torch.device(device_string) +torch_dtype = torch.float32 if device_string == "cpu" else torch.float16 + +if "caption" in modules: + print("Initializing an image captioning model...") + captioning_processor = AutoProcessor.from_pretrained(captioning_model) + if "blip" in captioning_model: + captioning_transformer = BlipForConditionalGeneration.from_pretrained( + captioning_model, torch_dtype=torch_dtype + ).to(device) + else: + captioning_transformer = AutoModelForCausalLM.from_pretrained( + captioning_model, torch_dtype=torch_dtype + ).to(device) + +if "summarize" in modules: + print("Initializing a text summarization model...") + summarization_tokenizer = AutoTokenizer.from_pretrained(summarization_model) + summarization_transformer = AutoModelForSeq2SeqLM.from_pretrained( + summarization_model, torch_dtype=torch_dtype + ).to(device) + +if "classify" in modules: + print("Initializing a sentiment classification pipeline...") + classification_pipe = pipeline( + "text-classification", + model=classification_model, + top_k=None, + device=device, + torch_dtype=torch_dtype, + ) + +if "sd" in modules and not sd_use_remote: + from diffusers import StableDiffusionPipeline + from diffusers import EulerAncestralDiscreteScheduler + + print("Initializing Stable Diffusion pipeline") + sd_device_string = ( + "cuda" if torch.cuda.is_available() and not args.sd_cpu else "cpu" + ) + sd_device = torch.device(sd_device_string) + sd_torch_dtype = torch.float32 if sd_device_string == "cpu" else torch.float16 + sd_pipe = StableDiffusionPipeline.from_pretrained( + sd_model, custom_pipeline="lpw_stable_diffusion", torch_dtype=sd_torch_dtype + ).to(sd_device) + sd_pipe.safety_checker = lambda images, clip_input: (images, False) + sd_pipe.enable_attention_slicing() + # pipe.scheduler = KarrasVeScheduler.from_config(pipe.scheduler.config) + sd_pipe.scheduler = EulerAncestralDiscreteScheduler.from_config( + sd_pipe.scheduler.config + ) +elif "sd" in modules and sd_use_remote: + print("Initializing Stable Diffusion connection") + try: + sd_remote = webuiapi.WebUIApi( + host=sd_remote_host, port=sd_remote_port, use_https=sd_remote_ssl + ) + if sd_remote_auth: + username, password = sd_remote_auth.split(":") + sd_remote.set_auth(username, password) + sd_remote.util_wait_for_ready() + except Exception as e: + # remote sd from modules + print( + f"{Fore.RED}{Style.BRIGHT}Could not connect to remote SD backend at http{'s' if sd_remote_ssl else ''}://{sd_remote_host}:{sd_remote_port}! Disabling SD module...{Style.RESET_ALL}" + ) + modules.remove("sd") + +if "tts" in modules: + print("tts module is deprecated. Please use silero-tts instead.") + modules.remove("tts") + modules.append("silero-tts") + + +if "silero-tts" in modules: + if not os.path.exists(SILERO_SAMPLES_PATH): + os.makedirs(SILERO_SAMPLES_PATH) + print("Initializing Silero TTS server") + from silero_api_server import tts + + tts_service = tts.SileroTtsService(SILERO_SAMPLES_PATH) + if len(os.listdir(SILERO_SAMPLES_PATH)) == 0: + print("Generating Silero TTS samples...") + tts_service.update_sample_text(SILERO_SAMPLE_TEXT) + tts_service.generate_samples() + + +if "edge-tts" in modules: + print("Initializing Edge TTS client") + import tts_edge as edge + + +if "chromadb" in modules: + print("Initializing ChromaDB") + import chromadb + import posthog + from chromadb.config import Settings + from sentence_transformers import SentenceTransformer + + # Assume that the user wants in-memory unless a host is specified + # Also disable chromadb telemetry + posthog.capture = lambda *args, **kwargs: None + if args.chroma_host is None: + chromadb_client = chromadb.Client(Settings(anonymized_telemetry=False, persist_directory=args.chroma_folder, chroma_db_impl='duckdb+parquet')) + print(f"ChromaDB is running in-memory with persistence. Persistence is stored in {args.chroma_folder}. Can be cleared by deleting the folder or purging db.") + else: + chroma_port=( + args.chroma_port if args.chroma_port else DEFAULT_CHROMA_PORT + ) + chromadb_client = chromadb.Client( + Settings( + anonymized_telemetry=False, + chroma_api_impl="rest", + chroma_server_host=args.chroma_host, + chroma_server_http_port=chroma_port + ) + ) + print(f"ChromaDB is remotely configured at {args.chroma_host}:{chroma_port}") + + chromadb_embedder = SentenceTransformer(embedding_model) + chromadb_embed_fn = lambda *args, **kwargs: chromadb_embedder.encode(*args, **kwargs).tolist() + + # Check if the db is connected and running, otherwise tell the user + try: + chromadb_client.heartbeat() + print("Successfully pinged ChromaDB! Your client is successfully connected.") + except: + print("Could not ping ChromaDB! If you are running remotely, please check your host and port!") + +# Flask init +app = Flask(__name__) +CORS(app) # allow cross-domain requests +Compress(app) # compress responses +app.config["MAX_CONTENT_LENGTH"] = 100 * 1024 * 1024 + + +def require_module(name): + def wrapper(fn): + @wraps(fn) + def decorated_view(*args, **kwargs): + if name not in modules: + abort(403, "Module is disabled by config") + return fn(*args, **kwargs) + + return decorated_view + + return wrapper + + +# AI stuff +def classify_text(text: str) -> list: + output = classification_pipe( + text, + truncation=True, + max_length=classification_pipe.model.config.max_position_embeddings, + )[0] + return sorted(output, key=lambda x: x["score"], reverse=True) + + +def caption_image(raw_image: Image, max_new_tokens: int = 20) -> str: + inputs = captioning_processor(raw_image.convert("RGB"), return_tensors="pt").to( + device, torch_dtype + ) + outputs = captioning_transformer.generate(**inputs, max_new_tokens=max_new_tokens) + caption = captioning_processor.decode(outputs[0], skip_special_tokens=True) + return caption + + +def summarize_chunks(text: str, params: dict) -> str: + try: + return summarize(text, params) + except IndexError: + print( + "Sequence length too large for model, cutting text in half and calling again" + ) + new_params = params.copy() + new_params["max_length"] = new_params["max_length"] // 2 + new_params["min_length"] = new_params["min_length"] // 2 + return summarize_chunks( + text[: (len(text) // 2)], new_params + ) + summarize_chunks(text[(len(text) // 2) :], new_params) + + +def summarize(text: str, params: dict) -> str: + # Tokenize input + inputs = summarization_tokenizer(text, return_tensors="pt").to(device) + token_count = len(inputs[0]) + + bad_words_ids = [ + summarization_tokenizer(bad_word, add_special_tokens=False).input_ids + for bad_word in params["bad_words"] + ] + summary_ids = summarization_transformer.generate( + inputs["input_ids"], + num_beams=2, + max_new_tokens=max(token_count, int(params["max_length"])), + min_new_tokens=min(token_count, int(params["min_length"])), + repetition_penalty=float(params["repetition_penalty"]), + temperature=float(params["temperature"]), + length_penalty=float(params["length_penalty"]), + bad_words_ids=bad_words_ids, + ) + summary = summarization_tokenizer.batch_decode( + summary_ids, skip_special_tokens=True, clean_up_tokenization_spaces=True + )[0] + summary = normalize_string(summary) + return summary + + +def normalize_string(input: str) -> str: + output = " ".join(unicodedata.normalize("NFKC", input).strip().split()) + return output + + +def generate_image(data: dict) -> Image: + prompt = normalize_string(f'{data["prompt_prefix"]} {data["prompt"]}') + + if sd_use_remote: + image = sd_remote.txt2img( + prompt=prompt, + negative_prompt=data["negative_prompt"], + sampler_name=data["sampler"], + steps=data["steps"], + cfg_scale=data["scale"], + width=data["width"], + height=data["height"], + restore_faces=data["restore_faces"], + enable_hr=data["enable_hr"], + save_images=True, + send_images=True, + do_not_save_grid=False, + do_not_save_samples=False, + ).image + else: + image = sd_pipe( + prompt=prompt, + negative_prompt=data["negative_prompt"], + num_inference_steps=data["steps"], + guidance_scale=data["scale"], + width=data["width"], + height=data["height"], + ).images[0] + + image.save("./debug.png") + return image + + +def image_to_base64(image: Image, quality: int = 75) -> str: + buffer = BytesIO() + image.convert("RGB") + image.save(buffer, format="JPEG", quality=quality) + img_str = base64.b64encode(buffer.getvalue()).decode("utf-8") + return img_str + +# Reads an API key from an already existing file. If that file doesn't exist, create it. +if args.secure: + try: + with open("api_key.txt", "r") as txt: + api_key = txt.read().replace('\n', '') + except: + api_key = secrets.token_hex(5) + with open("api_key.txt", "w") as txt: + txt.write(api_key) + + print(f"Your API key is {api_key}") +elif args.share and args.secure != True: + print("WARNING: This instance is publicly exposed without an API key! It is highly recommended to restart with the \"--secure\" argument!") +else: + print("No API key given because you are running locally.") + +@app.before_request +def before_request(): + # Request time measuring + request.start_time = time.time() + + # Checks if an API key is present and valid, otherwise return unauthorized + # The options check is required so CORS doesn't get angry + try: + if request.method != 'OPTIONS' and args.secure and request.authorization.token != api_key: + print(f"WARNING: Unauthorized API key access from {request.remote_addr}") + response = jsonify({ 'error': '401: Invalid API key' }) + response.status_code = 401 + return response + except Exception as e: + print(f"API key check error: {e}") + return "401 Unauthorized\n{}\n\n".format(e), 401 + + +@app.after_request +def after_request(response): + duration = time.time() - request.start_time + response.headers["X-Request-Duration"] = str(duration) + return response + + +@app.route("/", methods=["GET"]) +def index(): + with open("./README.md", "r", encoding="utf8") as f: + content = f.read() + return render_template_string(markdown.markdown(content, extensions=["tables"])) + + +@app.route("/api/extensions", methods=["GET"]) +def get_extensions(): + extensions = dict( + { + "extensions": [ + { + "name": "not-supported", + "metadata": { + "display_name": """Extensions serving using Extensions API is no longer supported. Please update the mod from: https://github.com/Cohee1207/SillyTavern""", + "requires": [], + "assets": [], + }, + } + ] + } + ) + return jsonify(extensions) + + +@app.route("/api/caption", methods=["POST"]) +@require_module("caption") +def api_caption(): + data = request.get_json() + + if "image" not in data or not isinstance(data["image"], str): + abort(400, '"image" is required') + + image = Image.open(BytesIO(base64.b64decode(data["image"]))) + image = image.convert("RGB") + image.thumbnail((512, 512)) + caption = caption_image(image) + thumbnail = image_to_base64(image) + print("Caption:", caption, sep="\n") + gc.collect() + return jsonify({"caption": caption, "thumbnail": thumbnail}) + + +@app.route("/api/summarize", methods=["POST"]) +@require_module("summarize") +def api_summarize(): + data = request.get_json() + + if "text" not in data or not isinstance(data["text"], str): + abort(400, '"text" is required') + + params = DEFAULT_SUMMARIZE_PARAMS.copy() + + if "params" in data and isinstance(data["params"], dict): + params.update(data["params"]) + + print("Summary input:", data["text"], sep="\n") + summary = summarize_chunks(data["text"], params) + print("Summary output:", summary, sep="\n") + gc.collect() + return jsonify({"summary": summary}) + + +@app.route("/api/classify", methods=["POST"]) +@require_module("classify") +def api_classify(): + data = request.get_json() + + if "text" not in data or not isinstance(data["text"], str): + abort(400, '"text" is required') + + print("Classification input:", data["text"], sep="\n") + classification = classify_text(data["text"]) + print("Classification output:", classification, sep="\n") + gc.collect() + return jsonify({"classification": classification}) + + +@app.route("/api/classify/labels", methods=["GET"]) +@require_module("classify") +def api_classify_labels(): + classification = classify_text("") + labels = [x["label"] for x in classification] + return jsonify({"labels": labels}) + + +@app.route("/api/image", methods=["POST"]) +@require_module("sd") +def api_image(): + required_fields = { + "prompt": str, + } + + optional_fields = { + "steps": 30, + "scale": 6, + "sampler": "DDIM", + "width": 512, + "height": 512, + "restore_faces": False, + "enable_hr": False, + "prompt_prefix": PROMPT_PREFIX, + "negative_prompt": NEGATIVE_PROMPT, + } + + data = request.get_json() + + # Check required fields + for field, field_type in required_fields.items(): + if field not in data or not isinstance(data[field], field_type): + abort(400, f'"{field}" is required') + + # Set optional fields to default values if not provided + for field, default_value in optional_fields.items(): + type_match = ( + (int, float) + if isinstance(default_value, (int, float)) + else type(default_value) + ) + if field not in data or not isinstance(data[field], type_match): + data[field] = default_value + + try: + print("SD inputs:", data, sep="\n") + image = generate_image(data) + base64image = image_to_base64(image, quality=90) + return jsonify({"image": base64image}) + except RuntimeError as e: + abort(400, str(e)) + + +@app.route("/api/image/model", methods=["POST"]) +@require_module("sd") +def api_image_model_set(): + data = request.get_json() + + if not sd_use_remote: + abort(400, "Changing model for local sd is not supported.") + if "model" not in data or not isinstance(data["model"], str): + abort(400, '"model" is required') + + old_model = sd_remote.util_get_current_model() + sd_remote.util_set_model(data["model"], find_closest=False) + # sd_remote.util_set_model(data['model']) + sd_remote.util_wait_for_ready() + new_model = sd_remote.util_get_current_model() + + return jsonify({"previous_model": old_model, "current_model": new_model}) + + +@app.route("/api/image/model", methods=["GET"]) +@require_module("sd") +def api_image_model_get(): + model = sd_model + + if sd_use_remote: + model = sd_remote.util_get_current_model() + + return jsonify({"model": model}) + + +@app.route("/api/image/models", methods=["GET"]) +@require_module("sd") +def api_image_models(): + models = [sd_model] + + if sd_use_remote: + models = sd_remote.util_get_model_names() + + return jsonify({"models": models}) + + +@app.route("/api/image/samplers", methods=["GET"]) +@require_module("sd") +def api_image_samplers(): + samplers = ["Euler a"] + + if sd_use_remote: + samplers = [sampler["name"] for sampler in sd_remote.get_samplers()] + + return jsonify({"samplers": samplers}) + + +@app.route("/api/modules", methods=["GET"]) +def get_modules(): + return jsonify({"modules": modules}) + + +@app.route("/api/tts/speakers", methods=["GET"]) +@require_module("silero-tts") +def tts_speakers(): + voices = [ + { + "name": speaker, + "voice_id": speaker, + "preview_url": f"{str(request.url_root)}api/tts/sample/{speaker}", + } + for speaker in tts_service.get_speakers() + ] + return jsonify(voices) + + +@app.route("/api/tts/generate", methods=["POST"]) +@require_module("silero-tts") +def tts_generate(): + voice = request.get_json() + if "text" not in voice or not isinstance(voice["text"], str): + abort(400, '"text" is required') + if "speaker" not in voice or not isinstance(voice["speaker"], str): + abort(400, '"speaker" is required') + # Remove asterisks + voice["text"] = voice["text"].replace("*", "") + try: + audio = tts_service.generate(voice["speaker"], voice["text"]) + return send_file(audio, mimetype="audio/x-wav") + except Exception as e: + print(e) + abort(500, voice["speaker"]) + + +@app.route("/api/tts/sample/", methods=["GET"]) +@require_module("silero-tts") +def tts_play_sample(speaker: str): + return send_from_directory(SILERO_SAMPLES_PATH, f"{speaker}.wav") + + +@app.route("/api/edge-tts/list", methods=["GET"]) +@require_module("edge-tts") +def edge_tts_list(): + voices = edge.get_voices() + return jsonify(voices) + + +@app.route("/api/edge-tts/generate", methods=["POST"]) +@require_module("edge-tts") +def edge_tts_generate(): + data = request.get_json() + if "text" not in data or not isinstance(data["text"], str): + abort(400, '"text" is required') + if "voice" not in data or not isinstance(data["voice"], str): + abort(400, '"voice" is required') + if "rate" in data and isinstance(data['rate'], int): + rate = data['rate'] + else: + rate = 0 + # Remove asterisks + data["text"] = data["text"].replace("*", "") + try: + audio = edge.generate_audio(text=data["text"], voice=data["voice"], rate=rate) + return Response(audio, mimetype="audio/mpeg") + except Exception as e: + print(e) + abort(500, data["voice"]) + + +@app.route("/api/chromadb", methods=["POST"]) +@require_module("chromadb") +def chromadb_add_messages(): + data = request.get_json() + if "chat_id" not in data or not isinstance(data["chat_id"], str): + abort(400, '"chat_id" is required') + if "messages" not in data or not isinstance(data["messages"], list): + abort(400, '"messages" is required') + + chat_id_md5 = hashlib.md5(data["chat_id"].encode()).hexdigest() + collection = chromadb_client.get_or_create_collection( + name=f"chat-{chat_id_md5}", embedding_function=chromadb_embed_fn + ) + + documents = [m["content"] for m in data["messages"]] + ids = [m["id"] for m in data["messages"]] + metadatas = [ + {"role": m["role"], "date": m["date"], "meta": m.get("meta", "")} + for m in data["messages"] + ] + + collection.upsert( + ids=ids, + documents=documents, + metadatas=metadatas, + ) + + return jsonify({"count": len(ids)}) + + +@app.route("/api/chromadb/purge", methods=["POST"]) +@require_module("chromadb") +def chromadb_purge(): + data = request.get_json() + if "chat_id" not in data or not isinstance(data["chat_id"], str): + abort(400, '"chat_id" is required') + + chat_id_md5 = hashlib.md5(data["chat_id"].encode()).hexdigest() + collection = chromadb_client.get_or_create_collection( + name=f"chat-{chat_id_md5}", embedding_function=chromadb_embed_fn + ) + + count = collection.count() + collection.delete() + #Write deletion to persistent folder + chromadb_client.persist() + print("ChromaDB embeddings deleted", count) + return 'Ok', 200 + + +@app.route("/api/chromadb/query", methods=["POST"]) +@require_module("chromadb") +def chromadb_query(): + data = request.get_json() + if "chat_id" not in data or not isinstance(data["chat_id"], str): + abort(400, '"chat_id" is required') + if "query" not in data or not isinstance(data["query"], str): + abort(400, '"query" is required') + + if "n_results" not in data or not isinstance(data["n_results"], int): + n_results = 1 + else: + n_results = data["n_results"] + + chat_id_md5 = hashlib.md5(data["chat_id"].encode()).hexdigest() + collection = chromadb_client.get_or_create_collection( + name=f"chat-{chat_id_md5}", embedding_function=chromadb_embed_fn + ) + + n_results = min(collection.count(), n_results) + query_result = collection.query( + query_texts=[data["query"]], + n_results=n_results, + ) + + documents = query_result["documents"][0] + ids = query_result["ids"][0] + metadatas = query_result["metadatas"][0] + distances = query_result["distances"][0] + + messages = [ + { + "id": ids[i], + "date": metadatas[i]["date"], + "role": metadatas[i]["role"], + "meta": metadatas[i]["meta"], + "content": documents[i], + "distance": distances[i], + } + for i in range(len(ids)) + ] + + return jsonify(messages) + + +@app.route("/api/chromadb/export", methods=["POST"]) +@require_module("chromadb") +def chromadb_export(): + data = request.get_json() + if "chat_id" not in data or not isinstance(data["chat_id"], str): + abort(400, '"chat_id" is required') + + chat_id_md5 = hashlib.md5(data["chat_id"].encode()).hexdigest() + collection = chromadb_client.get_or_create_collection( + name=f"chat-{chat_id_md5}", embedding_function=chromadb_embed_fn + ) + collection_content = collection.get() + documents = collection_content.get('documents', []) + ids = collection_content.get('ids', []) + metadatas = collection_content.get('metadatas', []) + + content = [ + { + "id": ids[i], + "metadata": metadatas[i], + "document": documents[i], + } + for i in range(len(ids)) + ] + + export = { + "chat_id": data["chat_id"], + "content": content + } + + + return jsonify(export) + +@app.route("/api/chromadb/import", methods=["POST"]) +@require_module("chromadb") +def chromadb_import(): + data = request.get_json() + content = data['content'] + if "chat_id" not in data or not isinstance(data["chat_id"], str): + abort(400, '"chat_id" is required') + + chat_id_md5 = hashlib.md5(data["chat_id"].encode()).hexdigest() + collection = chromadb_client.get_or_create_collection( + name=f"chat-{chat_id_md5}", embedding_function=chromadb_embed_fn + ) + + documents = [item['document'] for item in content] + metadatas = [item['metadata'] for item in content] + ids = [item['id'] for item in content] + + + collection.upsert(documents=documents, metadatas=metadatas, ids=ids) + + return jsonify({"count": len(ids)}) + +app.run(host=host, port=port) diff --git a/tts_edge.py b/tts_edge.py new file mode 100644 index 0000000000000000000000000000000000000000..7031e18e0b836ec64254e5637f7e10b775c871a0 --- /dev/null +++ b/tts_edge.py @@ -0,0 +1,34 @@ +import io +import edge_tts +import asyncio + + +def get_voices(): + voices = asyncio.run(edge_tts.list_voices()) + return voices + + +async def _iterate_chunks(audio): + async for chunk in audio.stream(): + if chunk["type"] == "audio": + yield chunk["data"] + + +async def _async_generator_to_list(async_gen): + result = [] + async for item in async_gen: + result.append(item) + return result + + +def generate_audio(text: str, voice: str, rate: int) -> bytes: + sign = '+' if rate > 0 else '-' + rate = f'{sign}{abs(rate)}%' + audio = edge_tts.Communicate(text=text, voice=voice, rate=rate) + chunks = asyncio.run(_async_generator_to_list(_iterate_chunks(audio))) + buffer = io.BytesIO() + + for chunk in chunks: + buffer.write(chunk) + + return buffer.getvalue() diff --git a/tts_samples/en_0.wav b/tts_samples/en_0.wav new file mode 100644 index 0000000000000000000000000000000000000000..cf0b895801ee29d2d1a3cbf4179d23852aa5562b Binary files /dev/null and b/tts_samples/en_0.wav differ diff --git a/tts_samples/en_1.wav b/tts_samples/en_1.wav new file mode 100644 index 0000000000000000000000000000000000000000..cd4c1f9a57b22f768b1f0c93c01c32a399932455 Binary files /dev/null and b/tts_samples/en_1.wav differ diff --git a/tts_samples/en_10.wav b/tts_samples/en_10.wav new file mode 100644 index 0000000000000000000000000000000000000000..22bce4147624cfa1772c9a3601c86c397367bcff Binary files /dev/null and b/tts_samples/en_10.wav differ diff --git a/tts_samples/en_11.wav b/tts_samples/en_11.wav new file mode 100644 index 0000000000000000000000000000000000000000..a208fa40c4429e92cd4dbecb9f9c3c713874656d Binary files /dev/null and b/tts_samples/en_11.wav differ diff --git a/tts_samples/en_114.wav b/tts_samples/en_114.wav new file mode 100644 index 0000000000000000000000000000000000000000..361e7e9f4be035e030835b2ac17c5262859c7896 Binary files /dev/null and b/tts_samples/en_114.wav differ diff --git a/tts_samples/en_115.wav b/tts_samples/en_115.wav new file mode 100644 index 0000000000000000000000000000000000000000..b0d0988f1d5e615216273c9f8a35fa32b6142c17 Binary files /dev/null and b/tts_samples/en_115.wav differ diff --git a/tts_samples/en_116.wav b/tts_samples/en_116.wav new file mode 100644 index 0000000000000000000000000000000000000000..dc903b0e7efc807cc489d8070dea423fbdd06eeb Binary files /dev/null and b/tts_samples/en_116.wav differ diff --git a/tts_samples/en_117.wav b/tts_samples/en_117.wav new file mode 100644 index 0000000000000000000000000000000000000000..dbe708c5d1f6b894c8d4185732df9571148cf1bb Binary files /dev/null and b/tts_samples/en_117.wav differ diff --git a/tts_samples/en_12.wav b/tts_samples/en_12.wav new file mode 100644 index 0000000000000000000000000000000000000000..78e4a8b87ff9ecf2cabbedae513ae1cbf4e46b82 Binary files /dev/null and b/tts_samples/en_12.wav differ diff --git a/tts_samples/en_13.wav b/tts_samples/en_13.wav new file mode 100644 index 0000000000000000000000000000000000000000..24275094c50d8cc8eb7985d06b102fa46a674f15 Binary files /dev/null and b/tts_samples/en_13.wav differ diff --git a/tts_samples/en_14.wav b/tts_samples/en_14.wav new file mode 100644 index 0000000000000000000000000000000000000000..41393be1920ff6a3641f2c7fa22a4481f381e0ea Binary files /dev/null and b/tts_samples/en_14.wav differ diff --git a/tts_samples/en_15.wav b/tts_samples/en_15.wav new file mode 100644 index 0000000000000000000000000000000000000000..8462926ceab158938ea3e2a35ed1805b8fc715aa Binary files /dev/null and b/tts_samples/en_15.wav differ diff --git a/tts_samples/en_16.wav b/tts_samples/en_16.wav new file mode 100644 index 0000000000000000000000000000000000000000..e66c91cf1aff07342e45de706a22935962036445 Binary files /dev/null and b/tts_samples/en_16.wav differ diff --git a/tts_samples/en_17.wav b/tts_samples/en_17.wav new file mode 100644 index 0000000000000000000000000000000000000000..29e7a815172cb00b5d9f33c8fd28a0f167dd770c Binary files /dev/null and b/tts_samples/en_17.wav differ diff --git a/tts_samples/en_18.wav b/tts_samples/en_18.wav new file mode 100644 index 0000000000000000000000000000000000000000..240260b1ebd5467d80b77278baa2c97f0eb9ff61 Binary files /dev/null and b/tts_samples/en_18.wav differ diff --git a/tts_samples/en_19.wav b/tts_samples/en_19.wav new file mode 100644 index 0000000000000000000000000000000000000000..0e9e9e1d68603ea74ec66c351a252ca39df0592e Binary files /dev/null and b/tts_samples/en_19.wav differ diff --git a/tts_samples/en_2.wav b/tts_samples/en_2.wav new file mode 100644 index 0000000000000000000000000000000000000000..cd47f06b20f581b09681f67b8fb0b4e6ed610918 Binary files /dev/null and b/tts_samples/en_2.wav differ diff --git a/tts_samples/en_20.wav b/tts_samples/en_20.wav new file mode 100644 index 0000000000000000000000000000000000000000..9e0246100815bfd7ffa6ce98dd6443b4d0f9a292 Binary files /dev/null and b/tts_samples/en_20.wav differ diff --git a/tts_samples/en_21.wav b/tts_samples/en_21.wav new file mode 100644 index 0000000000000000000000000000000000000000..6d6e70077d6bb642040c6d900c8d9f2393effcea Binary files /dev/null and b/tts_samples/en_21.wav differ diff --git a/tts_samples/en_22.wav b/tts_samples/en_22.wav new file mode 100644 index 0000000000000000000000000000000000000000..162d86dbb1ca3e3f813f0e3bf00df9ba81dd25b8 Binary files /dev/null and b/tts_samples/en_22.wav differ diff --git a/tts_samples/en_23.wav b/tts_samples/en_23.wav new file mode 100644 index 0000000000000000000000000000000000000000..075395390e750456655028fcd134c25a6e68506e Binary files /dev/null and b/tts_samples/en_23.wav differ diff --git a/tts_samples/en_24.wav b/tts_samples/en_24.wav new file mode 100644 index 0000000000000000000000000000000000000000..c5f0d98dce84cbdd4e1d2036a559919e79ce841b Binary files /dev/null and b/tts_samples/en_24.wav differ diff --git a/tts_samples/en_25.wav b/tts_samples/en_25.wav new file mode 100644 index 0000000000000000000000000000000000000000..a60b107b495d8fb430905ae6671172e1262d6132 Binary files /dev/null and b/tts_samples/en_25.wav differ diff --git a/tts_samples/en_26.wav b/tts_samples/en_26.wav new file mode 100644 index 0000000000000000000000000000000000000000..d97742831700168bf04310edc42104d61e9f1edf Binary files /dev/null and b/tts_samples/en_26.wav differ diff --git a/tts_samples/en_27.wav b/tts_samples/en_27.wav new file mode 100644 index 0000000000000000000000000000000000000000..622cde347214932bb21a2d8909083274886ba6b6 Binary files /dev/null and b/tts_samples/en_27.wav differ diff --git a/tts_samples/en_28.wav b/tts_samples/en_28.wav new file mode 100644 index 0000000000000000000000000000000000000000..6f29462405a1e45b27491cc4bd7cea8678073178 Binary files /dev/null and b/tts_samples/en_28.wav differ diff --git a/tts_samples/en_29.wav b/tts_samples/en_29.wav new file mode 100644 index 0000000000000000000000000000000000000000..79171d7088d80d94d44e4e191c58754d8c61dea3 Binary files /dev/null and b/tts_samples/en_29.wav differ diff --git a/tts_samples/en_3.wav b/tts_samples/en_3.wav new file mode 100644 index 0000000000000000000000000000000000000000..201f72216e459f1fa22561661b0a954cc1445efd Binary files /dev/null and b/tts_samples/en_3.wav differ diff --git a/tts_samples/en_30.wav b/tts_samples/en_30.wav new file mode 100644 index 0000000000000000000000000000000000000000..0909b3e5b3f9f4d49cd7d87ce00ea920b1b38084 Binary files /dev/null and b/tts_samples/en_30.wav differ diff --git a/tts_samples/en_31.wav b/tts_samples/en_31.wav new file mode 100644 index 0000000000000000000000000000000000000000..775354ac13aafae98e8aa2abbdc466931401605a Binary files /dev/null and b/tts_samples/en_31.wav differ diff --git a/tts_samples/en_32.wav b/tts_samples/en_32.wav new file mode 100644 index 0000000000000000000000000000000000000000..29abb9807fd3ea42c205af3800dbedc634008f77 Binary files /dev/null and b/tts_samples/en_32.wav differ diff --git a/tts_samples/en_33.wav b/tts_samples/en_33.wav new file mode 100644 index 0000000000000000000000000000000000000000..9f13c730d4446fcc66b510eaabf250785729e8e9 Binary files /dev/null and b/tts_samples/en_33.wav differ diff --git a/tts_samples/en_34.wav b/tts_samples/en_34.wav new file mode 100644 index 0000000000000000000000000000000000000000..7209ce26a208ef5c0af88b8e0020c84c9a1f4d63 Binary files /dev/null and b/tts_samples/en_34.wav differ diff --git a/tts_samples/en_35.wav b/tts_samples/en_35.wav new file mode 100644 index 0000000000000000000000000000000000000000..88c4296680e665c02801a69395e20f0529a5dd3a Binary files /dev/null and b/tts_samples/en_35.wav differ diff --git a/tts_samples/en_36.wav b/tts_samples/en_36.wav new file mode 100644 index 0000000000000000000000000000000000000000..30a9a0cd53f7d4c8cb479317924b1de9e4f66e5f Binary files /dev/null and b/tts_samples/en_36.wav differ diff --git a/tts_samples/en_37.wav b/tts_samples/en_37.wav new file mode 100644 index 0000000000000000000000000000000000000000..094dbbfe525bf839250d6feca2fa84c8620ce1be Binary files /dev/null and b/tts_samples/en_37.wav differ diff --git a/tts_samples/en_38.wav b/tts_samples/en_38.wav new file mode 100644 index 0000000000000000000000000000000000000000..cfd197b1f8b555d6dbe19ddbdc169e35cfffbd0a Binary files /dev/null and b/tts_samples/en_38.wav differ diff --git a/tts_samples/en_39.wav b/tts_samples/en_39.wav new file mode 100644 index 0000000000000000000000000000000000000000..3c83a38920e16d32d36c150fe3053a7cdbc17726 Binary files /dev/null and b/tts_samples/en_39.wav differ diff --git a/tts_samples/en_4.wav b/tts_samples/en_4.wav new file mode 100644 index 0000000000000000000000000000000000000000..c39f1340450debb1e36b2a646b7a52a297154ae8 Binary files /dev/null and b/tts_samples/en_4.wav differ diff --git a/tts_samples/en_40.wav b/tts_samples/en_40.wav new file mode 100644 index 0000000000000000000000000000000000000000..592084ce134f4de50526df8a360f69d04ea3daa8 Binary files /dev/null and b/tts_samples/en_40.wav differ diff --git a/tts_samples/en_41.wav b/tts_samples/en_41.wav new file mode 100644 index 0000000000000000000000000000000000000000..8f5d4596b3707fd7ff858c9eae0ddfd6c66f3e9c Binary files /dev/null and b/tts_samples/en_41.wav differ diff --git a/tts_samples/en_42.wav b/tts_samples/en_42.wav new file mode 100644 index 0000000000000000000000000000000000000000..b0a8198cd3e9c02b16bf735d954584266131cd2a Binary files /dev/null and b/tts_samples/en_42.wav differ diff --git a/tts_samples/en_43.wav b/tts_samples/en_43.wav new file mode 100644 index 0000000000000000000000000000000000000000..0a0f8ee19307ab1d9f4226821ea63cb90be6ae66 Binary files /dev/null and b/tts_samples/en_43.wav differ diff --git a/tts_samples/en_44.wav b/tts_samples/en_44.wav new file mode 100644 index 0000000000000000000000000000000000000000..3cac802a96a0d82029ca5fe3c79f4aecc0cb6a41 Binary files /dev/null and b/tts_samples/en_44.wav differ diff --git a/tts_samples/en_45.wav b/tts_samples/en_45.wav new file mode 100644 index 0000000000000000000000000000000000000000..21a012a0d0e5ce441ccf06a848583ead60b28a5e Binary files /dev/null and b/tts_samples/en_45.wav differ diff --git a/tts_samples/en_46.wav b/tts_samples/en_46.wav new file mode 100644 index 0000000000000000000000000000000000000000..f5bc0b67d64ffc6bd6ef2a35bce9c536e6192446 Binary files /dev/null and b/tts_samples/en_46.wav differ diff --git a/tts_samples/en_47.wav b/tts_samples/en_47.wav new file mode 100644 index 0000000000000000000000000000000000000000..f0407872d08ba2e526d070745c7ac211a9530385 Binary files /dev/null and b/tts_samples/en_47.wav differ diff --git a/tts_samples/en_48.wav b/tts_samples/en_48.wav new file mode 100644 index 0000000000000000000000000000000000000000..cf431e8b530cf88adf7bffd43d5c4a711a7e90be Binary files /dev/null and b/tts_samples/en_48.wav differ diff --git a/tts_samples/en_49.wav b/tts_samples/en_49.wav new file mode 100644 index 0000000000000000000000000000000000000000..4fe382f652d6ab4829cd7c05783574aa0a960ddd Binary files /dev/null and b/tts_samples/en_49.wav differ diff --git a/tts_samples/en_5.wav b/tts_samples/en_5.wav new file mode 100644 index 0000000000000000000000000000000000000000..7e9a49f78320d2655a54bff3f0922051460a5ded Binary files /dev/null and b/tts_samples/en_5.wav differ diff --git a/tts_samples/en_50.wav b/tts_samples/en_50.wav new file mode 100644 index 0000000000000000000000000000000000000000..4f1f0a459a34be10b7935d99a4a70bb2b75ec3ed Binary files /dev/null and b/tts_samples/en_50.wav differ diff --git a/tts_samples/en_51.wav b/tts_samples/en_51.wav new file mode 100644 index 0000000000000000000000000000000000000000..3a5165dfed2b830b3550034c4a1aa2c0facda722 Binary files /dev/null and b/tts_samples/en_51.wav differ diff --git a/tts_samples/en_52.wav b/tts_samples/en_52.wav new file mode 100644 index 0000000000000000000000000000000000000000..13c5e9d9769f8f8defda17a54d2f85a107b257ae Binary files /dev/null and b/tts_samples/en_52.wav differ diff --git a/tts_samples/en_53.wav b/tts_samples/en_53.wav new file mode 100644 index 0000000000000000000000000000000000000000..58e73e10b3649d003eed620bfbbc6fc01778c7f2 Binary files /dev/null and b/tts_samples/en_53.wav differ diff --git a/tts_samples/en_54.wav b/tts_samples/en_54.wav new file mode 100644 index 0000000000000000000000000000000000000000..2fb0cfc69502a816a2b424e55b08324e481ca6c3 Binary files /dev/null and b/tts_samples/en_54.wav differ diff --git a/tts_samples/en_55.wav b/tts_samples/en_55.wav new file mode 100644 index 0000000000000000000000000000000000000000..6ac094e0745e0d8065dce3942af4f0bb4dd1232f Binary files /dev/null and b/tts_samples/en_55.wav differ diff --git a/tts_samples/en_56.wav b/tts_samples/en_56.wav new file mode 100644 index 0000000000000000000000000000000000000000..8261f8f8723d85257eb31c1232c7cf18d8e4f62e Binary files /dev/null and b/tts_samples/en_56.wav differ diff --git a/tts_samples/en_57.wav b/tts_samples/en_57.wav new file mode 100644 index 0000000000000000000000000000000000000000..2e807664f4e84452069307b3a4dfa43712edfa32 Binary files /dev/null and b/tts_samples/en_57.wav differ diff --git a/tts_samples/en_58.wav b/tts_samples/en_58.wav new file mode 100644 index 0000000000000000000000000000000000000000..576f505ef3e9c5041cadefc3f85b7f2aa03d28e2 Binary files /dev/null and b/tts_samples/en_58.wav differ diff --git a/tts_samples/en_59.wav b/tts_samples/en_59.wav new file mode 100644 index 0000000000000000000000000000000000000000..d8551b537b7519b54d32de9180bac6ea32e20d74 Binary files /dev/null and b/tts_samples/en_59.wav differ diff --git a/tts_samples/en_6.wav b/tts_samples/en_6.wav new file mode 100644 index 0000000000000000000000000000000000000000..cd312884349a93671be4f804db4b170f0184f07c Binary files /dev/null and b/tts_samples/en_6.wav differ diff --git a/tts_samples/en_60.wav b/tts_samples/en_60.wav new file mode 100644 index 0000000000000000000000000000000000000000..a6784293cc9a6fc9a001d534a1643cc0db22ae20 Binary files /dev/null and b/tts_samples/en_60.wav differ diff --git a/tts_samples/en_61.wav b/tts_samples/en_61.wav new file mode 100644 index 0000000000000000000000000000000000000000..c7490b557af6d016e917e30651baaaf95b5f5ee2 Binary files /dev/null and b/tts_samples/en_61.wav differ diff --git a/tts_samples/en_62.wav b/tts_samples/en_62.wav new file mode 100644 index 0000000000000000000000000000000000000000..3a0eea6d7e94f15f584d3c90c306ce8d1d342b9c Binary files /dev/null and b/tts_samples/en_62.wav differ diff --git a/tts_samples/en_63.wav b/tts_samples/en_63.wav new file mode 100644 index 0000000000000000000000000000000000000000..30d885aec6d690e3ea235051a9d11f2e7c24e2e1 Binary files /dev/null and b/tts_samples/en_63.wav differ diff --git a/tts_samples/en_64.wav b/tts_samples/en_64.wav new file mode 100644 index 0000000000000000000000000000000000000000..2b59028499921648cc91c3b77c021ef0fb238428 Binary files /dev/null and b/tts_samples/en_64.wav differ diff --git a/tts_samples/en_65.wav b/tts_samples/en_65.wav new file mode 100644 index 0000000000000000000000000000000000000000..6908f663de319e983eff451c3182116e834f2b9f Binary files /dev/null and b/tts_samples/en_65.wav differ diff --git a/tts_samples/en_66.wav b/tts_samples/en_66.wav new file mode 100644 index 0000000000000000000000000000000000000000..1cd13462ecba6a6bf51848532ef7fddb0a1d2272 Binary files /dev/null and b/tts_samples/en_66.wav differ diff --git a/tts_samples/en_67.wav b/tts_samples/en_67.wav new file mode 100644 index 0000000000000000000000000000000000000000..bcabb01eb7691089113f234c25fcc5be9c1923f5 Binary files /dev/null and b/tts_samples/en_67.wav differ diff --git a/tts_samples/en_68.wav b/tts_samples/en_68.wav new file mode 100644 index 0000000000000000000000000000000000000000..100eec2722ddf12be87bb751e54f41ba873233d9 Binary files /dev/null and b/tts_samples/en_68.wav differ diff --git a/tts_samples/en_69.wav b/tts_samples/en_69.wav new file mode 100644 index 0000000000000000000000000000000000000000..7fd472cfe6dc4f185056c2c177b8c417f2e1837d Binary files /dev/null and b/tts_samples/en_69.wav differ diff --git a/tts_samples/en_7.wav b/tts_samples/en_7.wav new file mode 100644 index 0000000000000000000000000000000000000000..6294aac97ae0e2143c6ffd3735d4d7c9c1f8d786 Binary files /dev/null and b/tts_samples/en_7.wav differ diff --git a/tts_samples/en_70.wav b/tts_samples/en_70.wav new file mode 100644 index 0000000000000000000000000000000000000000..0173a3e6e869724c711038059e8472eae29c4ccd Binary files /dev/null and b/tts_samples/en_70.wav differ diff --git a/tts_samples/en_71.wav b/tts_samples/en_71.wav new file mode 100644 index 0000000000000000000000000000000000000000..cca3b7fa01bc878150291dca5ad3354d46161d8b Binary files /dev/null and b/tts_samples/en_71.wav differ diff --git a/tts_samples/en_72.wav b/tts_samples/en_72.wav new file mode 100644 index 0000000000000000000000000000000000000000..6791895448e4a4e2aef85acfef06be6152bcc7fd Binary files /dev/null and b/tts_samples/en_72.wav differ diff --git a/tts_samples/en_73.wav b/tts_samples/en_73.wav new file mode 100644 index 0000000000000000000000000000000000000000..535b1d7e28c4b9e4b6e0905079d5774ae3613b6d Binary files /dev/null and b/tts_samples/en_73.wav differ diff --git a/tts_samples/en_74.wav b/tts_samples/en_74.wav new file mode 100644 index 0000000000000000000000000000000000000000..9baa790e0d17189e3a38a4fa48ffb876e9ded173 Binary files /dev/null and b/tts_samples/en_74.wav differ diff --git a/tts_samples/en_75.wav b/tts_samples/en_75.wav new file mode 100644 index 0000000000000000000000000000000000000000..cd2b3ba085059c77cc3462b0a11a709334ece1cf Binary files /dev/null and b/tts_samples/en_75.wav differ diff --git a/tts_samples/en_76.wav b/tts_samples/en_76.wav new file mode 100644 index 0000000000000000000000000000000000000000..bc09734d53fddde5c751cad17fc81c263537d262 Binary files /dev/null and b/tts_samples/en_76.wav differ diff --git a/tts_samples/en_77.wav b/tts_samples/en_77.wav new file mode 100644 index 0000000000000000000000000000000000000000..5449b1f9f3f19e535e6717b49fc7fad52f13a68b Binary files /dev/null and b/tts_samples/en_77.wav differ diff --git a/tts_samples/en_78.wav b/tts_samples/en_78.wav new file mode 100644 index 0000000000000000000000000000000000000000..46843ae0028ad4e6d547d4e83aadd48a5f08886d Binary files /dev/null and b/tts_samples/en_78.wav differ diff --git a/tts_samples/en_79.wav b/tts_samples/en_79.wav new file mode 100644 index 0000000000000000000000000000000000000000..3cde5044967dac98e13b6b163db2af3f121bc4af Binary files /dev/null and b/tts_samples/en_79.wav differ diff --git a/tts_samples/en_8.wav b/tts_samples/en_8.wav new file mode 100644 index 0000000000000000000000000000000000000000..5169a2be020a136cd50f2c1546240145093a8918 Binary files /dev/null and b/tts_samples/en_8.wav differ diff --git a/tts_samples/en_80.wav b/tts_samples/en_80.wav new file mode 100644 index 0000000000000000000000000000000000000000..34fd4ab10ba75dc3c0e55d1d414b6d3b89ab57ce Binary files /dev/null and b/tts_samples/en_80.wav differ diff --git a/tts_samples/en_81.wav b/tts_samples/en_81.wav new file mode 100644 index 0000000000000000000000000000000000000000..a39784fb6cd78cc9fe5686d3225e1256496b069a Binary files /dev/null and b/tts_samples/en_81.wav differ diff --git a/tts_samples/en_82.wav b/tts_samples/en_82.wav new file mode 100644 index 0000000000000000000000000000000000000000..8a459daefd87df081885452d297e0aedf0115e81 Binary files /dev/null and b/tts_samples/en_82.wav differ diff --git a/tts_samples/en_83.wav b/tts_samples/en_83.wav new file mode 100644 index 0000000000000000000000000000000000000000..4e34ad50246a6c85e0c68bf349e83e73a476a714 Binary files /dev/null and b/tts_samples/en_83.wav differ diff --git a/tts_samples/en_84.wav b/tts_samples/en_84.wav new file mode 100644 index 0000000000000000000000000000000000000000..085e751bcfd359f1cea31aaf101ac0a86092babc Binary files /dev/null and b/tts_samples/en_84.wav differ diff --git a/tts_samples/en_85.wav b/tts_samples/en_85.wav new file mode 100644 index 0000000000000000000000000000000000000000..de71ae98a378bd42b2afc20aa6b68d2a6298f8e8 Binary files /dev/null and b/tts_samples/en_85.wav differ diff --git a/tts_samples/en_86.wav b/tts_samples/en_86.wav new file mode 100644 index 0000000000000000000000000000000000000000..dbbb7096fe92b608cb8af20b419261f02471e32d Binary files /dev/null and b/tts_samples/en_86.wav differ diff --git a/tts_samples/en_87.wav b/tts_samples/en_87.wav new file mode 100644 index 0000000000000000000000000000000000000000..961e063ed737aed610f5fd16ebde8a6e320a90cf Binary files /dev/null and b/tts_samples/en_87.wav differ diff --git a/tts_samples/en_88.wav b/tts_samples/en_88.wav new file mode 100644 index 0000000000000000000000000000000000000000..98df7579b45a4bd366a7eeff70934d42eba3b87c Binary files /dev/null and b/tts_samples/en_88.wav differ diff --git a/tts_samples/en_89.wav b/tts_samples/en_89.wav new file mode 100644 index 0000000000000000000000000000000000000000..446bdc5d257386adfb0c078177f863e0a4f3c37d Binary files /dev/null and b/tts_samples/en_89.wav differ diff --git a/tts_samples/en_9.wav b/tts_samples/en_9.wav new file mode 100644 index 0000000000000000000000000000000000000000..23387cc66439a8e208b35ff1d2f3257aef3260a7 Binary files /dev/null and b/tts_samples/en_9.wav differ diff --git a/tts_samples/en_90.wav b/tts_samples/en_90.wav new file mode 100644 index 0000000000000000000000000000000000000000..ddbd0f15679a823f707c1d07e0928586f5b72dee Binary files /dev/null and b/tts_samples/en_90.wav differ diff --git a/tts_samples/en_91.wav b/tts_samples/en_91.wav new file mode 100644 index 0000000000000000000000000000000000000000..79bd6d9210ae6cafeaacacccf30d3204c869a118 Binary files /dev/null and b/tts_samples/en_91.wav differ diff --git a/tts_samples/en_92.wav b/tts_samples/en_92.wav new file mode 100644 index 0000000000000000000000000000000000000000..b9aae831a406df66d5e2b396d318f7c7453d0a39 Binary files /dev/null and b/tts_samples/en_92.wav differ diff --git a/tts_samples/en_93.wav b/tts_samples/en_93.wav new file mode 100644 index 0000000000000000000000000000000000000000..4b7384946970d50b46861b82a7fb539310f3d7af Binary files /dev/null and b/tts_samples/en_93.wav differ diff --git a/tts_samples/en_94.wav b/tts_samples/en_94.wav new file mode 100644 index 0000000000000000000000000000000000000000..b1e4676a47fb4650780beb7774e0d31cdf16f7eb Binary files /dev/null and b/tts_samples/en_94.wav differ