Merge branch 'DrewThomasson:v25' into v25
94
Dockerfile
@@ -16,7 +16,6 @@ RUN apt-get update && \
|
||||
# Install Rust compiler
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
# Install UniDic (non-torch dependent)
|
||||
RUN pip install --no-cache-dir unidic-lite unidic && \
|
||||
@@ -31,74 +30,61 @@ ARG TORCH_VERSION=""
|
||||
# Add parameter to control whether to skip the XTTS test
|
||||
ARG SKIP_XTTS_TEST="false"
|
||||
|
||||
# Copy the application
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
|
||||
# Extract torch versions from requirements.txt or set to empty strings if not found
|
||||
RUN TORCH_VERSION_REQ=$(grep -E "^torch==" requirements.txt | cut -d'=' -f3 || echo "") && \
|
||||
TORCHAUDIO_VERSION_REQ=$(grep -E "^torchaudio==" requirements.txt | cut -d'=' -f3 || echo "") && \
|
||||
TORCHVISION_VERSION_REQ=$(grep -E "^torchvision==" requirements.txt | cut -d'=' -f3 || echo "") && \
|
||||
echo "Found in requirements: torch==$TORCH_VERSION_REQ torchaudio==$TORCHAUDIO_VERSION_REQ torchvision==$TORCHVISION_VERSION_REQ"
|
||||
|
||||
# Install PyTorch with CUDA support if specified
|
||||
# Install requirements.txt or PyTorch variants based on TORCH_VERSION
|
||||
RUN if [ ! -z "$TORCH_VERSION" ]; then \
|
||||
# Check if we need to use specific versions or get the latest
|
||||
if [ ! -z "$TORCH_VERSION_REQ" ] && [ ! -z "$TORCHVISION_VERSION_REQ" ] && [ ! -z "$TORCHAUDIO_VERSION_REQ" ]; then \
|
||||
echo "Using specific versions from requirements.txt" && \
|
||||
TORCH_SPEC="torch==${TORCH_VERSION_REQ}" && \
|
||||
TORCHVISION_SPEC="torchvision==${TORCHVISION_VERSION_REQ}" && \
|
||||
TORCHAUDIO_SPEC="torchaudio==${TORCHAUDIO_VERSION_REQ}"; \
|
||||
else \
|
||||
echo "Using latest versions for the selected variant" && \
|
||||
TORCH_SPEC="torch" && \
|
||||
TORCHVISION_SPEC="torchvision" && \
|
||||
TORCHAUDIO_SPEC="torchaudio"; \
|
||||
fi && \
|
||||
\
|
||||
# Check if TORCH_VERSION contains "cuda" and extract version number
|
||||
if echo "$TORCH_VERSION" | grep -q "cuda"; then \
|
||||
CUDA_VERSION=$(echo "$TORCH_VERSION" | sed 's/cuda//g') && \
|
||||
echo "Detected CUDA version: $CUDA_VERSION" && \
|
||||
echo "Attempting to install PyTorch nightly for CUDA $CUDA_VERSION..." && \
|
||||
#if ! pip install --no-cache-dir --pre $TORCH_SPEC $TORCHVISION_SPEC $TORCHAUDIO_SPEC --index-url https://download.pytorch.org/whl/nightly/cu${CUDA_VERSION}; then \
|
||||
if ! pip install --no-cache-dir --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu${CUDA_VERSION}; then \
|
||||
echo "❌ Nightly build for CUDA $CUDA_VERSION not available or failed" && \
|
||||
echo "🔄 Trying stable release for CUDA $CUDA_VERSION..." && \
|
||||
#if pip install --no-cache-dir $TORCH_SPEC $TORCHVISION_SPEC $TORCHAUDIO_SPEC --extra-index-url https://download.pytorch.org/whl/cu${CUDA_VERSION}; then \
|
||||
if pip install --no-cache-dir torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu${CUDA_VERSION}; then \
|
||||
echo "✅ Successfully installed stable PyTorch for CUDA $CUDA_VERSION"; \
|
||||
else \
|
||||
echo "❌ Both nightly and stable builds failed for CUDA $CUDA_VERSION"; \
|
||||
echo "💡 This CUDA version may not be supported by PyTorch"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
\
|
||||
# Special handling for CUDA 11.8
|
||||
if [ "$CUDA_VERSION" = "118" ]; then \
|
||||
echo "Installing PyTorch for CUDA 11.8..." && \
|
||||
pip install --no-cache-dir --upgrade -r requirements.txt && pip install pyannote-audio==3.4.0 && pip install --no-cache-dir --upgrade torch==2.7.1 torchvision==2.7.1 torchaudio==2.7.1 --index-url https://download.pytorch.org/whl/cu118; \
|
||||
elif [ "$CUDA_VERSION" = "128" ]; then \
|
||||
echo "Installing PyTorch for CUDA 12.8..." && \
|
||||
pip install --no-cache-dir --upgrade -r requirements.txt && pip install --no-cache-dir --upgrade torch==2.7.1 torchaudio==2.7.1 --index-url https://download.pytorch.org/whl/cu128; \
|
||||
else \
|
||||
echo "✅ Successfully installed nightly PyTorch for CUDA $CUDA_VERSION"; \
|
||||
echo "Attempting to install stable PyTorch for CUDA $CUDA_VERSION..." && \
|
||||
if ! pip install --no-cache-dir --upgrade -r requirements.txt && pip install --no-cache-dir --upgrade torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu${CUDA_VERSION}; then \
|
||||
echo "❌ Stable build for CUDA $CUDA_VERSION not available or failed" && \
|
||||
echo "🔄 Trying nightly release for CUDA $CUDA_VERSION..." && \
|
||||
if pip install --no-cache-dir --upgrade -r requirements.txt && pip install --no-cache-dir --upgrade --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu${CUDA_VERSION}; then \
|
||||
echo "✅ Successfully installed nightly PyTorch for CUDA $CUDA_VERSION"; \
|
||||
else \
|
||||
echo "❌ Both stable and nightly builds failed for CUDA $CUDA_VERSION"; \
|
||||
echo "💡 This CUDA version may not be supported by PyTorch"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
else \
|
||||
echo "✅ Successfully installed stable PyTorch for CUDA $CUDA_VERSION"; \
|
||||
fi; \
|
||||
fi; \
|
||||
else \
|
||||
# Handle non-CUDA cases (existing functionality)
|
||||
# Handle non-CUDA cases
|
||||
case "$TORCH_VERSION" in \
|
||||
"rocm") \
|
||||
# Using the correct syntax for ROCm PyTorch installation
|
||||
pip install --no-cache-dir $TORCH_SPEC $TORCHVISION_SPEC $TORCHAUDIO_SPEC --extra-index-url https://download.pytorch.org/whl/rocm6.2 \
|
||||
pip install --no-cache-dir --upgrade -r requirements.txt && pip install --no-cache-dir --upgrade torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.2 \
|
||||
;; \
|
||||
"xpu") \
|
||||
# Install PyTorch with Intel XPU support through IPEX
|
||||
pip install --no-cache-dir $TORCH_SPEC $TORCHVISION_SPEC $TORCHAUDIO_SPEC && \
|
||||
pip install --no-cache-dir --upgrade -r requirements.txt && pip install --no-cache-dir --upgrade torch torchvision torchaudio && \
|
||||
pip install --no-cache-dir intel-extension-for-pytorch --extra-index-url https://pytorch-extension.intel.com/release-whl/stable/xpu/us/ \
|
||||
;; \
|
||||
"cpu") \
|
||||
pip install --no-cache-dir $TORCH_SPEC $TORCHVISION_SPEC $TORCHAUDIO_SPEC --extra-index-url https://download.pytorch.org/whl/cpu \
|
||||
pip install --no-cache-dir --upgrade -r requirements.txt && pip install --no-cache-dir --upgrade torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu \
|
||||
;; \
|
||||
*) \
|
||||
pip install --no-cache-dir $TORCH_VERSION \
|
||||
echo "Installing custom PyTorch specification: $TORCH_VERSION" && \
|
||||
pip install --no-cache-dir --upgrade -r requirements.txt && pip install --no-cache-dir --upgrade $TORCH_VERSION \
|
||||
;; \
|
||||
esac; \
|
||||
fi && \
|
||||
# Install remaining requirements, skipping torch packages that might be there
|
||||
grep -v -E "^torch==|^torchvision==|^torchaudio==|^torchvision$" requirements.txt > requirements_no_torch.txt && \
|
||||
pip install --no-cache-dir --upgrade -r requirements_no_torch.txt && \
|
||||
rm requirements_no_torch.txt; \
|
||||
fi; \
|
||||
else \
|
||||
# Install all requirements as specified
|
||||
echo "No TORCH_VERSION specified, using packages from requirements.txt" && \
|
||||
pip install --no-cache-dir --upgrade -r requirements.txt; \
|
||||
fi
|
||||
|
||||
@@ -114,9 +100,6 @@ RUN if [ "$SKIP_XTTS_TEST" != "true" ]; then \
|
||||
echo "Skipping XTTS test run as requested."; \
|
||||
fi
|
||||
|
||||
# Copy the application
|
||||
COPY . /app
|
||||
|
||||
# Expose the required port
|
||||
EXPOSE 7860
|
||||
# Start the Gradio app with the required flag
|
||||
@@ -126,3 +109,12 @@ ENTRYPOINT ["python", "app.py", "--script_mode", "full_docker"]
|
||||
#docker build --pull --build-arg BASE_IMAGE=athomasson2/ebook2audiobook:latest -t your-image-name .
|
||||
#The --pull flag forces Docker to always try to pull the latest version of the image, even if it already exists locally.
|
||||
#Without --pull, Docker will only use the local version if it exists, which might not be the latest.
|
||||
|
||||
# Example build commands:
|
||||
# For CUDA 11.8: docker build --build-arg TORCH_VERSION=cuda118 -t your-image-name .
|
||||
# For CUDA 12.8: docker build --build-arg TORCH_VERSION=cuda128 -t your-image-name .
|
||||
# For CUDA 12.1: docker build --build-arg TORCH_VERSION=cuda121 -t your-image-name .
|
||||
# For ROCm: docker build --build-arg TORCH_VERSION=rocm -t your-image-name .
|
||||
# For CPU: docker build --build-arg TORCH_VERSION=cpu -t your-image-name .
|
||||
# For XPU: docker build --build-arg TORCH_VERSION=xpu -t your-image-name .
|
||||
# Default (no TORCH_VERSION): docker build -t your-image-name .
|
||||
|
||||
143
README.md
@@ -83,18 +83,18 @@ https://github.com/user-attachments/assets/81c4baad-117e-4db5-ac86-efc2b7fea921
|
||||
- [Basic Headless Usage](#basic--usage)
|
||||
- [Headless Custom XTTS Model Usage](#example-of-custom-model-zip-upload)
|
||||
- [Help command output](#help-command-output)
|
||||
- [Run Remotely](#run-remotely)
|
||||
- [Run Remotely](#run-remotely)
|
||||
- [Docker](#docker-compose)
|
||||
- [Docker Compose (Recommended)](#docker-compose)
|
||||
- [Docker Compose Headless](#compose-headless)
|
||||
- [Compose Build Arguments](#compose-build-arguments)
|
||||
- [Compose container file locations](#compose-container-file-locations)
|
||||
- [Common Docker issues](#common-docker-issues)
|
||||
- [Docker Build (Manual)](https://github.com/DrewThomasson/ebook2audiobook/wiki/Manual-Docker-Guide)
|
||||
|
||||
- [Fine Tuned TTS models](#fine-tuned-tts-models)
|
||||
- [Collection of Fine-Tuned TTS Models](#fine-tuned-tts-collection)
|
||||
- [Train XTTSv2](#fine-tune-your-own-xttsv2-model)
|
||||
- [Docker](#docker-gpu-options)
|
||||
- [GPU options](#docker-gpu-options)
|
||||
- [Docker Run](#running-the-pre-built-docker-container)
|
||||
- [Docker Build](#building-the-docker-container)
|
||||
- [Docker Compose](#docker-compose)
|
||||
- [Docker headless guide](#docker-headless-guide)
|
||||
- [Docker container file locations](#docker-container-file-locations)
|
||||
- [Common Docker issues](#common-docker-issues)
|
||||
- [Supported eBook Formats](#supported-ebook-formats)
|
||||
- [Output Formats](#output-formats)
|
||||
- [Updating to Latest Version](#updating-to-latest-version)
|
||||
@@ -169,9 +169,9 @@ cd ebook2audiobook
|
||||
|
||||
1. **Open the Web App**: Click the URL provided in the terminal to access the web app and convert eBooks. `http://localhost:7860/`
|
||||
2. **For Public Link**:
|
||||
`python app.py --share` (all OS)
|
||||
`./ebook2audiobook.sh --share` (Linux/MacOS)
|
||||
`ebook2audiobook.cmd --share` (Windows)
|
||||
`python app.py --share` (all OS)
|
||||
|
||||
> [!IMPORTANT]
|
||||
**If the script is stopped and run again, you need to refresh your gradio GUI interface<br>
|
||||
@@ -333,84 +333,11 @@ NOTE: in gradio/gui mode, to cancel a running conversion, just click on the [X]
|
||||
|
||||
TIP: if it needs some more pauses, just add '###' or '[pause]' between the words you wish more pause. one [pause] equals to 1.4 seconds
|
||||
|
||||
#### Docker GPU Options
|
||||
|
||||
Available pre-build tags: `latest` (CUDA 11.8)
|
||||
#### Edit: IF GPU isn't detected then you'll have to build the image -> [Building the Docker Container](#building-the-docker-container)
|
||||
|
||||
|
||||
|
||||
#### Running the pre-built Docker Container
|
||||
|
||||
-Run with CPU only
|
||||
```powershell
|
||||
docker run --pull always --rm -p 7860:7860 athomasson2/ebook2audiobook
|
||||
```
|
||||
-Run with GPU Speedup (NVIDIA compatible only)
|
||||
```powershell
|
||||
docker run --pull always --rm --gpus all -p 7860:7860 athomasson2/ebook2audiobook
|
||||
```
|
||||
|
||||
This command will start the Gradio interface on port 7860.(localhost:7860)
|
||||
- For more options add the parameter `--help`
|
||||
|
||||
|
||||
#### Building the Docker Container
|
||||
- You can build the docker image with the command:
|
||||
```powershell
|
||||
docker build -t athomasson2/ebook2audiobook .
|
||||
```
|
||||
#### Avalible Docker Build Arguments
|
||||
|
||||
`--build-arg TORCH_VERSION=cuda118` Available tags: [cuda121, cuda118, cuda128, rocm, xpu, cpu]
|
||||
|
||||
All CUDA version numbers should work, Ex: CUDA 11.6-> cuda116
|
||||
|
||||
`--build-arg SKIP_XTTS_TEST=true` (Saves space by not baking XTTSv2 model into docker image)
|
||||
|
||||
|
||||
## Docker container file locations
|
||||
All ebook2audiobooks will have the base dir of `/app/`
|
||||
For example:
|
||||
`tmp` = `/app/tmp`
|
||||
`audiobooks` = `/app/audiobooks`
|
||||
|
||||
|
||||
## Docker headless guide
|
||||
|
||||
> [!IMPORTANT]
|
||||
**For simpler headless setup use the [Compose](#compose-headless).** <br>
|
||||
|
||||
- Before you do run this you need to create a dir named "input-folder" in your current dir
|
||||
which will be linked, This is where you can put your input files for the docker image to see
|
||||
```bash
|
||||
mkdir input-folder && mkdir Audiobooks
|
||||
```
|
||||
- In the command below swap out **YOUR_INPUT_FILE.TXT** with the name of your input file
|
||||
```bash
|
||||
docker run --pull always --rm \
|
||||
-v $(pwd)/input-folder:/app/input_folder \
|
||||
-v $(pwd)/audiobooks:/app/audiobooks \
|
||||
athomasson2/ebook2audiobook \
|
||||
--headless --ebook /input_folder/YOUR_EBOOK_FILE
|
||||
```
|
||||
- The output Audiobooks will be found in the Audiobook folder which will also be located
|
||||
in your local dir you ran this docker command in
|
||||
|
||||
|
||||
## To get the help command for the other parameters this program has you can run this
|
||||
|
||||
```bash
|
||||
docker run --pull always --rm athomasson2/ebook2audiobook --help
|
||||
|
||||
```
|
||||
That will output this
|
||||
[Help command output](#help-command-output)
|
||||
|
||||
|
||||
### Docker Compose
|
||||
This project uses Docker Compose to run locally. You can enable or disable GPU support
|
||||
by setting either `*gpu-enabled` or `*gpu-disabled` in `docker-compose.yml`
|
||||
|
||||
For pre-built image enable `#image: docker.io/athomasson2/ebook2audiobook:latest` in `docker-compose.yml`
|
||||
|
||||
|
||||
|
||||
#### Steps to Run
|
||||
@@ -421,46 +348,48 @@ by setting either `*gpu-enabled` or `*gpu-disabled` in `docker-compose.yml`
|
||||
```
|
||||
2. **Set GPU Support (disabled by default)**
|
||||
To enable GPU support, modify `docker-compose.yml` and change `*gpu-disabled` to `*gpu-enabled`
|
||||
3. **Start the service:**
|
||||
4. **Start the service:**
|
||||
```bash
|
||||
# Docker
|
||||
docker-compose up -d # To rebuild add --build
|
||||
docker-compose up -d # To rebuild add --build
|
||||
# To stop -> docker-compose down
|
||||
|
||||
# Podman
|
||||
podman compose -f podman-compose.yml up -d # To rebuild add --build
|
||||
# To stop -> podman compose -f podman-compose.yml down
|
||||
```
|
||||
4. **Access the service:**
|
||||
5. **Access the service:**
|
||||
The service will be available at http://localhost:7860.
|
||||
|
||||
|
||||
### Compose Build Arguments
|
||||
|
||||
```bash
|
||||
SKIP_XTTS_TEST: "true" # (Saves space by not baking xtts model into docker image)
|
||||
TORCH_VERSION: cuda118 # Available tags: [cuda121, cuda118, cuda128, rocm, xpu, cpu] # All CUDA version numbers should work, Ex: CUDA 11.6-> cuda116
|
||||
```
|
||||
|
||||
|
||||
### Compose Headless
|
||||
|
||||
[Headless Wiki for more info](https://github.com/DrewThomasson/ebook2audiobook/wiki/Docker-Compose-Headless-guide)
|
||||
|
||||
```bash
|
||||
A headless example is already contained within the `docker-compose.yml` file.
|
||||
|
||||
The `docker-compose.yml` file will act as the base dir for any headless commands added.
|
||||
```
|
||||
|
||||
### Compose container file locations
|
||||
|
||||
```bash
|
||||
By Default: All compose containers share the contents your local `ebook2audiobook` folder
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Common Docker Issues
|
||||
### Common Docker Issues
|
||||
|
||||
- My NVIDIA GPU isnt being detected?? -> [GPU ISSUES Wiki Page](https://github.com/DrewThomasson/ebook2audiobook/wiki/GPU-ISSUES)
|
||||
|
||||
- `python: can't open file '/home/user/app/app.py': [Errno 2] No such file or directory` (Just remove all post arguments as I replaced the `CMD` with `ENTRYPOINT` in the [Dockerfile](Dockerfile))
|
||||
- Example: `docker run --pull always athomasson2/ebook2audiobook app.py --script_mode full_docker` - > corrected - > `docker run --pull always athomasson2/ebook2audiobook`
|
||||
- Arguments can be easily added like this now `docker run --pull always athomasson2/ebook2audiobook --share`
|
||||
|
||||
- Docker gets stuck downloading Fine-Tuned models.
|
||||
(This does not happen for every computer but some appear to run into this issue)
|
||||
Disabling the progress bar appears to fix the issue,
|
||||
as discussed [here in #191](https://github.com/DrewThomasson/ebook2audiobook/issues/191)
|
||||
Example of adding this fix in the `docker run` command
|
||||
```Dockerfile
|
||||
docker run --pull always --rm --gpus all -e HF_HUB_DISABLE_PROGRESS_BARS=1 -e HF_HUB_ENABLE_HF_TRANSFER=0 \
|
||||
-p 7860:7860 athomasson2/ebook2audiobook
|
||||
```
|
||||
|
||||
|
||||
## Fine Tuned TTS models
|
||||
#### Fine Tune your own XTTSv2 model
|
||||
|
||||
@@ -405,6 +405,115 @@ else
|
||||
return 0
|
||||
}
|
||||
|
||||
function create_macos_app_bundle {
|
||||
local APP_NAME="ebook2audiobook"
|
||||
local APP_BUNDLE="$HOME/Applications/$APP_NAME.app"
|
||||
local CONTENTS="$APP_BUNDLE/Contents"
|
||||
local MACOS="$CONTENTS/MacOS"
|
||||
local RESOURCES="$CONTENTS/Resources"
|
||||
local ICON_PATH="$SCRIPT_DIR/icons/mac/appIcon.icns"
|
||||
|
||||
echo "🚀 Creating $APP_NAME.app bundle..."
|
||||
mkdir -p "$MACOS" "$RESOURCES"
|
||||
|
||||
# Create the executable script inside the bundle
|
||||
cat > "$MACOS/$APP_NAME" << EOF
|
||||
#!/bin/bash
|
||||
|
||||
# Create a temporary script file to run in Terminal
|
||||
TEMP_SCRIPT=\$(mktemp)
|
||||
|
||||
cat > "\$TEMP_SCRIPT" << 'SCRIPT'
|
||||
#!/bin/bash
|
||||
cd "$SCRIPT_DIR"
|
||||
conda deactivate
|
||||
bash ebook2audiobook.sh
|
||||
|
||||
# Wait 10 seconds for the server to start
|
||||
sleep 10
|
||||
|
||||
# Open the browser
|
||||
open http://localhost:7860/
|
||||
|
||||
SCRIPT
|
||||
|
||||
chmod +x "\$TEMP_SCRIPT"
|
||||
|
||||
# Open Terminal and run the script
|
||||
open -a Terminal "\$TEMP_SCRIPT"
|
||||
|
||||
# Clean up the temp script after 60 seconds
|
||||
sleep 60
|
||||
rm "\$TEMP_SCRIPT"
|
||||
|
||||
EOF
|
||||
|
||||
chmod +x "$MACOS/$APP_NAME"
|
||||
|
||||
# Copy the icon to the bundle
|
||||
if [ -f "$ICON_PATH" ]; then
|
||||
cp "$ICON_PATH" "$RESOURCES/AppIcon.icns"
|
||||
echo "✓ Icon copied to bundle"
|
||||
else
|
||||
echo "⚠️ Warning: Icon not found at $ICON_PATH"
|
||||
fi
|
||||
|
||||
# Create the Info.plist file (required for macOS app bundles)
|
||||
cat > "$CONTENTS/Info.plist" << 'PLIST'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>ebook2audiobook</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.local.ebook2audiobook</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>ebook2audiobook</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.9</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>AppIcon</string>
|
||||
</dict>
|
||||
</plist>
|
||||
PLIST
|
||||
|
||||
echo "✓ Info.plist created"
|
||||
|
||||
# Update macOS cache to recognize the new app
|
||||
touch "$APP_BUNDLE"
|
||||
|
||||
echo ""
|
||||
echo "✅ Application bundle created successfully!"
|
||||
echo "📍 Location: $APP_BUNDLE"
|
||||
echo ""
|
||||
}
|
||||
|
||||
function create_linux_app_launcher {
|
||||
# Linux desktop entry creation goes here
|
||||
return 0
|
||||
}
|
||||
|
||||
function create_app_bundle {
|
||||
if [[ "$OSTYPE" = "darwin"* ]]; then
|
||||
create_macos_app_bundle
|
||||
elif [[ "$OSTYPE" = "linux"* ]]; then
|
||||
create_linux_app_launcher
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$SCRIPT_MODE" = "$FULL_DOCKER" ]; then
|
||||
python app.py --script_mode "$SCRIPT_MODE" "${ARGS[@]}"
|
||||
conda deactivate
|
||||
@@ -421,6 +530,7 @@ else
|
||||
conda init > /dev/null 2>&1
|
||||
source $CONDA_ENV
|
||||
conda activate "$SCRIPT_DIR/$PYTHON_ENV"
|
||||
create_app_bundle
|
||||
python app.py --script_mode "$SCRIPT_MODE" "${ARGS[@]}"
|
||||
conda deactivate
|
||||
conda deactivate
|
||||
@@ -431,4 +541,4 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
exit 0
|
||||
@@ -329,6 +329,22 @@ models = {
|
||||
"files": default_engine_settings[TTS_ENGINES['XTTSv2']]['files'],
|
||||
"samplerate": default_engine_settings[TTS_ENGINES['XTTSv2']]['samplerate']
|
||||
},
|
||||
"PeterGriffinFamilyGuy": {
|
||||
"lang": "eng",
|
||||
"repo": "drewThomasson/fineTunedTTSModels",
|
||||
"sub": "xtts-v2/eng/PeterGriffinFamilyGuy/",
|
||||
"voice": os.path.join(voices_dir, 'eng', 'adult', 'male', 'PeterGriffinFamilyGuy.wav'),
|
||||
"files": default_engine_settings[TTS_ENGINES['XTTSv2']]['files'],
|
||||
"samplerate": default_engine_settings[TTS_ENGINES['XTTSv2']]['samplerate']
|
||||
},
|
||||
"RafeBeckley": {
|
||||
"lang": "eng",
|
||||
"repo": "drewThomasson/fineTunedTTSModels",
|
||||
"sub": "xtts-v2/eng/RafeBeckley/",
|
||||
"voice": os.path.join(voices_dir, 'eng', 'adult', 'male', 'RafeBeckley.wav'),
|
||||
"files": default_engine_settings[TTS_ENGINES['XTTSv2']]['files'],
|
||||
"samplerate": default_engine_settings[TTS_ENGINES['XTTSv2']]['samplerate']
|
||||
},
|
||||
"RainyDayHeadSpace": {
|
||||
"lang": "eng",
|
||||
"repo": "drewThomasson/fineTunedTTSModels",
|
||||
@@ -496,3 +512,4 @@ models = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
tools/icons/appLogo.png
Normal file
|
After Width: | Height: | Size: 461 KiB |
173
tools/icons/generate-icons.py
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Multi-platform icon generator
|
||||
Converts appLogo.png into platform-specific formats and sizes
|
||||
Requires: Pillow (PIL), cairosvg (optional for SVG)
|
||||
|
||||
Installation:
|
||||
pip install Pillow cairosvg
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from PIL import Image
|
||||
|
||||
# Icon sizes for each platform
|
||||
ICON_SIZES = {
|
||||
'windows': [16, 24, 32, 48, 256],
|
||||
'mac': [16, 32, 64, 128, 256, 512, 1024],
|
||||
'linux': [16, 24, 32, 48, 64, 128, 256]
|
||||
}
|
||||
|
||||
def create_directories():
|
||||
"""Create output directories for each platform"""
|
||||
for platform in ICON_SIZES.keys():
|
||||
os.makedirs(f'icons/{platform}', exist_ok=True)
|
||||
print("✓ Directories created")
|
||||
|
||||
def resize_image(source_path, output_dir, sizes):
|
||||
"""Resize image to multiple sizes"""
|
||||
try:
|
||||
img = Image.open(source_path)
|
||||
# Convert to RGBA to ensure transparency support
|
||||
img = img.convert('RGBA')
|
||||
|
||||
for size in sizes:
|
||||
resized = img.resize((size, size), Image.Resampling.LANCZOS)
|
||||
output_path = f'{output_dir}/icon-{size}.png'
|
||||
resized.save(output_path, 'PNG')
|
||||
print(f" ✓ Generated {size}x{size} icon")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ Error resizing image: {e}")
|
||||
return False
|
||||
|
||||
def create_windows_ico(output_dir):
|
||||
"""Create Windows ICO file from PNGs"""
|
||||
try:
|
||||
sizes = ICON_SIZES['windows']
|
||||
images = []
|
||||
|
||||
for size in sizes:
|
||||
img_path = f'{output_dir}/icon-{size}.png'
|
||||
images.append(Image.open(img_path))
|
||||
|
||||
# Save as ICO with multiple sizes
|
||||
images[0].save(
|
||||
f'{output_dir}/appIcon.ico',
|
||||
format='ICO',
|
||||
sizes=[(size, size) for size in sizes]
|
||||
)
|
||||
print("✓ Windows ICO file created: icons/windows/appIcon.ico")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ Error creating ICO: {e}")
|
||||
return False
|
||||
|
||||
def create_mac_icns(output_dir):
|
||||
"""Create macOS ICNS file from PNGs (requires imagemagick or online conversion)"""
|
||||
try:
|
||||
import subprocess
|
||||
sizes = ICON_SIZES['mac']
|
||||
|
||||
# Create iconset directory
|
||||
iconset_dir = f'{output_dir}/appIcon.iconset'
|
||||
os.makedirs(iconset_dir, exist_ok=True)
|
||||
|
||||
for size in sizes:
|
||||
img_path = f'{output_dir}/icon-{size}.png'
|
||||
# macOS uses specific naming conventions
|
||||
scale = 2 if size > 256 else 1
|
||||
icon_name = f'icon_{size // scale}x{size // scale}'
|
||||
if scale == 2:
|
||||
icon_name += '@2x'
|
||||
|
||||
output_path = f'{iconset_dir}/{icon_name}.png'
|
||||
os.system(f'cp {img_path} {output_path}')
|
||||
|
||||
# Try to create ICNS using iconutil (macOS only) or convert
|
||||
try:
|
||||
subprocess.run(['iconutil', '-c', 'icns', '-o',
|
||||
f'{output_dir}/appIcon.icns', iconset_dir],
|
||||
check=True, capture_output=True)
|
||||
print("✓ macOS ICNS file created: icons/mac/appIcon.icns")
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
print("⚠ Note: iconutil not found. ICNS not created.")
|
||||
print(" On macOS, run: iconutil -c icns -o icons/mac/appIcon.icns icons/mac/appIcon.iconset")
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ Error creating ICNS: {e}")
|
||||
return False
|
||||
|
||||
def create_svg_copy(source_path, output_dir):
|
||||
"""Create SVG copy for Linux (optional, requires vector source)"""
|
||||
try:
|
||||
import shutil
|
||||
svg_path = source_path.replace('.png', '.svg')
|
||||
|
||||
if os.path.exists(svg_path):
|
||||
shutil.copy(svg_path, f'{output_dir}/appIcon.svg')
|
||||
print(f"✓ SVG icon copied: icons/linux/appIcon.svg")
|
||||
return True
|
||||
else:
|
||||
print("⚠ No SVG source found (optional for Linux)")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ Error copying SVG: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Main execution"""
|
||||
print("🎨 Multi-Platform Icon Generator\n")
|
||||
|
||||
# Find source image
|
||||
source_image = 'appLogo.png'
|
||||
if not os.path.exists(source_image):
|
||||
print(f"✗ Error: {source_image} not found in current directory")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Source: {source_image}\n")
|
||||
|
||||
# Create directories
|
||||
create_directories()
|
||||
print()
|
||||
|
||||
# Generate icons for each platform
|
||||
for platform, sizes in ICON_SIZES.items():
|
||||
print(f"Generating {platform.upper()} icons...")
|
||||
output_dir = f'icons/{platform}'
|
||||
|
||||
if not resize_image(source_image, output_dir, sizes):
|
||||
sys.exit(1)
|
||||
print()
|
||||
|
||||
# Create platform-specific formats
|
||||
print("Creating platform-specific formats...\n")
|
||||
|
||||
if not create_windows_ico('icons/windows'):
|
||||
print("⚠ Continuing despite ICO creation issue\n")
|
||||
|
||||
if not create_mac_icns('icons/mac'):
|
||||
print("⚠ Continuing despite ICNS creation issue\n")
|
||||
|
||||
if not create_svg_copy(source_image, 'icons/linux'):
|
||||
print("⚠ Continuing despite SVG copy issue\n")
|
||||
|
||||
print("✅ Icon generation complete!")
|
||||
print("\nOutput structure:")
|
||||
print(" icons/")
|
||||
print(" ├── windows/")
|
||||
print(" │ ├── appIcon.ico")
|
||||
print(" │ └── icon-*.png")
|
||||
print(" ├── mac/")
|
||||
print(" │ ├── appIcon.icns (if created)")
|
||||
print(" │ └── icon-*.png")
|
||||
print(" └── linux/")
|
||||
print(" ├── appIcon.svg (if available)")
|
||||
print(" └── icon-*.png")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
tools/icons/linux/icon-128.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
tools/icons/linux/icon-16.png
Normal file
|
After Width: | Height: | Size: 345 B |
BIN
tools/icons/linux/icon-24.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
tools/icons/linux/icon-256.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
tools/icons/linux/icon-32.png
Normal file
|
After Width: | Height: | Size: 876 B |
BIN
tools/icons/linux/icon-48.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
tools/icons/linux/icon-64.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
tools/icons/mac/appIcon.icns
Normal file
BIN
tools/icons/mac/appIcon.iconset/icon_128x128.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
tools/icons/mac/appIcon.iconset/icon_16x16.png
Normal file
|
After Width: | Height: | Size: 345 B |
BIN
tools/icons/mac/appIcon.iconset/icon_256x256.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
tools/icons/mac/appIcon.iconset/icon_256x256@2x.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
tools/icons/mac/appIcon.iconset/icon_32x32.png
Normal file
|
After Width: | Height: | Size: 876 B |
BIN
tools/icons/mac/appIcon.iconset/icon_512x512@2x.png
Normal file
|
After Width: | Height: | Size: 465 KiB |
BIN
tools/icons/mac/appIcon.iconset/icon_64x64.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
tools/icons/mac/icon-1024.png
Normal file
|
After Width: | Height: | Size: 465 KiB |
BIN
tools/icons/mac/icon-128.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
tools/icons/mac/icon-16.png
Normal file
|
After Width: | Height: | Size: 345 B |
BIN
tools/icons/mac/icon-256.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
tools/icons/mac/icon-32.png
Normal file
|
After Width: | Height: | Size: 876 B |
BIN
tools/icons/mac/icon-512.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
tools/icons/mac/icon-64.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
tools/icons/windows/appIcon.ico
Normal file
|
After Width: | Height: | Size: 367 B |
BIN
tools/icons/windows/icon-16.png
Normal file
|
After Width: | Height: | Size: 345 B |
BIN
tools/icons/windows/icon-24.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
tools/icons/windows/icon-256.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
tools/icons/windows/icon-32.png
Normal file
|
After Width: | Height: | Size: 876 B |
BIN
tools/icons/windows/icon-48.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |