current workign version using chatterbox.

This commit is contained in:
Steve White 2025-08-12 11:31:00 -05:00
parent aeb0f7b638
commit 948712bb3f
7 changed files with 99 additions and 48 deletions

View File

@ -359,7 +359,7 @@ The API uses the following directory structure (configurable in `app/config.py`)
- **Temporary Files**: `{PROJECT_ROOT}/tts_temp_outputs/`
### CORS Settings
- Allowed Origins: `http://localhost:8001`, `http://127.0.0.1:8001`
- Allowed Origins: `http://localhost:8001`, `http://127.0.0.1:8001` (plus any `FRONTEND_HOST:FRONTEND_PORT` when using `start_servers.py`)
- Allowed Methods: All
- Allowed Headers: All
- Credentials: Enabled

View File

@ -58,7 +58,7 @@ The application uses environment variables for configuration. Three `.env` files
- `VITE_DEV_SERVER_HOST`: Frontend development server host
#### CORS Configuration
- `CORS_ORIGINS`: Comma-separated list of allowed origins
- `CORS_ORIGINS`: Comma-separated list of allowed origins. When using `start_servers.py` with the default `FRONTEND_HOST=0.0.0.0` and no explicit `CORS_ORIGINS`, CORS will allow all origins (wildcard) to simplify development.
#### Device Configuration
- `DEVICE`: Device for TTS model (auto, cpu, cuda, mps)
@ -101,7 +101,7 @@ CORS_ORIGINS=http://localhost:3000
### Common Issues
1. **Permission Errors**: Ensure the `PROJECT_ROOT` directory is writable
2. **CORS Errors**: Check that your frontend URL is in `CORS_ORIGINS`
2. **CORS Errors**: Check that your frontend URL is in `CORS_ORIGINS`. (When using `start_servers.py`, your specified `FRONTEND_HOST:FRONTEND_PORT` will be autoincluded.)
3. **Model Loading Errors**: Verify `DEVICE` setting matches your hardware
4. **Path Errors**: Ensure all path variables point to existing, accessible directories

View File

@ -149,5 +149,5 @@ The application automatically:
- **"Skipping unknown speaker"**: Configure speaker in `speaker_data/speakers.yaml`
- **"Sample file not found"**: Verify audio files exist in `speaker_data/speaker_samples/`
- **Memory issues**: Use model reinitialization options for long content
- **CORS errors**: Check frontend/backend port configuration
- **CORS errors**: Check frontend/backend port configuration (frontend origin is auto-included when using `start_servers.py`)
- **Import errors**: Run `python import_helper.py` to check dependencies

View File

@ -6,20 +6,34 @@ from dotenv import load_dotenv
load_dotenv()
# Project root - can be overridden by environment variable
PROJECT_ROOT = Path(os.getenv("PROJECT_ROOT", Path(__file__).parent.parent.parent)).resolve()
PROJECT_ROOT = Path(
os.getenv("PROJECT_ROOT", Path(__file__).parent.parent.parent)
).resolve()
# Directory paths
SPEAKER_DATA_BASE_DIR = Path(os.getenv("SPEAKER_DATA_BASE_DIR", str(PROJECT_ROOT / "speaker_data")))
SPEAKER_SAMPLES_DIR = Path(os.getenv("SPEAKER_SAMPLES_DIR", str(SPEAKER_DATA_BASE_DIR / "speaker_samples")))
SPEAKERS_YAML_FILE = Path(os.getenv("SPEAKERS_YAML_FILE", str(SPEAKER_DATA_BASE_DIR / "speakers.yaml")))
SPEAKER_DATA_BASE_DIR = Path(
os.getenv("SPEAKER_DATA_BASE_DIR", str(PROJECT_ROOT / "speaker_data"))
)
SPEAKER_SAMPLES_DIR = Path(
os.getenv("SPEAKER_SAMPLES_DIR", str(SPEAKER_DATA_BASE_DIR / "speaker_samples"))
)
SPEAKERS_YAML_FILE = Path(
os.getenv("SPEAKERS_YAML_FILE", str(SPEAKER_DATA_BASE_DIR / "speakers.yaml"))
)
# TTS temporary output path (used by DialogProcessorService)
TTS_TEMP_OUTPUT_DIR = Path(os.getenv("TTS_TEMP_OUTPUT_DIR", str(PROJECT_ROOT / "tts_temp_outputs")))
TTS_TEMP_OUTPUT_DIR = Path(
os.getenv("TTS_TEMP_OUTPUT_DIR", str(PROJECT_ROOT / "tts_temp_outputs"))
)
# Final dialog output path (used by Dialog router and served by main app)
# These are stored within the 'backend' directory to be easily servable.
DIALOG_OUTPUT_PARENT_DIR = PROJECT_ROOT / "backend"
DIALOG_GENERATED_DIR = Path(os.getenv("DIALOG_GENERATED_DIR", str(DIALOG_OUTPUT_PARENT_DIR / "tts_generated_dialogs")))
DIALOG_GENERATED_DIR = Path(
os.getenv(
"DIALOG_GENERATED_DIR", str(DIALOG_OUTPUT_PARENT_DIR / "tts_generated_dialogs")
)
)
# Alias for clarity and backward compatibility
DIALOG_OUTPUT_DIR = DIALOG_GENERATED_DIR
@ -29,8 +43,26 @@ HOST = os.getenv("HOST", "0.0.0.0")
PORT = int(os.getenv("PORT", "8000"))
RELOAD = os.getenv("RELOAD", "true").lower() == "true"
# CORS configuration
CORS_ORIGINS = [origin.strip() for origin in os.getenv("CORS_ORIGINS", "http://localhost:8001,http://127.0.0.1:8001").split(",")]
# CORS configuration: determine allowed origins based on env & frontend binding
_cors_env = os.getenv("CORS_ORIGINS", "")
_frontend_host = os.getenv("FRONTEND_HOST")
_frontend_port = os.getenv("FRONTEND_PORT")
# If the dev server is bound to 0.0.0.0 (all interfaces), allow all origins
if _frontend_host == "0.0.0.0": # dev convenience when binding wildcard
CORS_ORIGINS = ["*"]
elif _cors_env:
# parse comma-separated origins, strip whitespace
CORS_ORIGINS = [origin.strip() for origin in _cors_env.split(",") if origin.strip()]
else:
# default to allow all origins in development
CORS_ORIGINS = ["*"]
# Auto-include specific frontend origin when not using wildcard CORS
if CORS_ORIGINS != ["*"] and _frontend_host and _frontend_port:
_frontend_origin = f"http://{_frontend_host.strip()}:{_frontend_port.strip()}"
if _frontend_origin not in CORS_ORIGINS:
CORS_ORIGINS.append(_frontend_origin)
# Device configuration
DEVICE = os.getenv("DEVICE", "auto")

View File

@ -13,8 +13,15 @@ const getEnvVar = (name, defaultValue) => {
};
// API Configuration
export const API_BASE_URL = getEnvVar('VITE_API_BASE_URL', 'http://localhost:8000');
export const API_BASE_URL_WITH_PREFIX = getEnvVar('VITE_API_BASE_URL_WITH_PREFIX', 'http://localhost:8000/api');
// Default to the same hostname as the frontend, on port 8000 (override via VITE_API_BASE_URL*)
const _defaultHost = (typeof window !== 'undefined' && window.location?.hostname) || 'localhost';
const _defaultPort = getEnvVar('VITE_API_BASE_URL_PORT', '8000');
const _defaultBase = `http://${_defaultHost}:${_defaultPort}`;
export const API_BASE_URL = getEnvVar('VITE_API_BASE_URL', _defaultBase);
export const API_BASE_URL_WITH_PREFIX = getEnvVar(
'VITE_API_BASE_URL_WITH_PREFIX',
`${_defaultBase}/api`
);
// For file serving (same as API_BASE_URL since files are served from the same server)
export const API_BASE_URL_FOR_FILES = API_BASE_URL;

View File

@ -28,3 +28,6 @@ dd3552d9-f4e8-49ed-9892-f9e67afcf23c:
2cdd6d3d-c533-44bf-a5f6-cc83bd089d32:
name: Grace
sample_path: speaker_samples/2cdd6d3d-c533-44bf-a5f6-cc83bd089d32.wav
3d3e85db-3d67-4488-94b2-ffc189fbb287:
name: RCB
sample_path: speaker_samples/3d3e85db-3d67-4488-94b2-ffc189fbb287.wav

View File

@ -14,28 +14,37 @@ from pathlib import Path
# Try to load environment variables, but don't fail if dotenv is not available
try:
from dotenv import load_dotenv
load_dotenv()
except ImportError:
print("python-dotenv not installed, using system environment variables only")
# Configuration
BACKEND_PORT = int(os.getenv('BACKEND_PORT', '8000'))
BACKEND_HOST = os.getenv('BACKEND_HOST', '0.0.0.0')
FRONTEND_PORT = int(os.getenv('FRONTEND_PORT', '8001'))
FRONTEND_HOST = os.getenv('FRONTEND_HOST', '127.0.0.1')
BACKEND_PORT = int(os.getenv("BACKEND_PORT", "8000"))
BACKEND_HOST = os.getenv("BACKEND_HOST", "0.0.0.0")
# Frontend host/port (for dev server binding)
FRONTEND_PORT = int(os.getenv("FRONTEND_PORT", "8001"))
FRONTEND_HOST = os.getenv("FRONTEND_HOST", "0.0.0.0")
# Export frontend host/port so backend CORS config can pick them up automatically
os.environ["FRONTEND_HOST"] = FRONTEND_HOST
os.environ["FRONTEND_PORT"] = str(FRONTEND_PORT)
# Get project root directory
PROJECT_ROOT = Path(__file__).parent.absolute()
def run_backend():
"""Run the backend FastAPI server"""
os.chdir(PROJECT_ROOT / "backend")
cmd = [
sys.executable, "-m", "uvicorn",
sys.executable,
"-m",
"uvicorn",
"app.main:app",
"--reload",
f"--host={BACKEND_HOST}",
f"--port={BACKEND_PORT}"
f"--port={BACKEND_PORT}",
]
print(f"\n{'='*50}")
@ -48,9 +57,10 @@ def run_backend():
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1
bufsize=1,
)
def run_frontend():
"""Run the frontend development server"""
frontend_dir = PROJECT_ROOT / "frontend"
@ -71,15 +81,17 @@ def run_frontend():
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1
bufsize=1,
)
def print_process_output(process, prefix):
"""Print process output with a prefix"""
for line in iter(process.stdout.readline, ''):
for line in iter(process.stdout.readline, ""):
if not line:
break
print(f"{prefix} | {line}", end='')
print(f"{prefix} | {line}", end="")
def main():
"""Main function to start both servers"""
@ -96,14 +108,10 @@ def main():
# Create threads to monitor and print output
backend_monitor = threading.Thread(
target=print_process_output,
args=(backend_process, "BACKEND"),
daemon=True
target=print_process_output, args=(backend_process, "BACKEND"), daemon=True
)
frontend_monitor = threading.Thread(
target=print_process_output,
args=(frontend_process, "FRONTEND"),
daemon=True
target=print_process_output, args=(frontend_process, "FRONTEND"), daemon=True
)
backend_monitor.start()
@ -134,5 +142,6 @@ def main():
except KeyboardInterrupt:
signal_handler(None, None)
if __name__ == "__main__":
main()